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
.ITmfRequest
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfBlockFilter
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfClearExperimentSignal
;
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
;
35 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
36 * that are part of a tracing experiment.
39 * @author Francois Chouinard
41 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
{
43 // ------------------------------------------------------------------------
45 // ------------------------------------------------------------------------
48 * The default index page size
50 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
52 // ------------------------------------------------------------------------
54 // ------------------------------------------------------------------------
57 * The set of traces that constitute the experiment
59 protected ITmfTrace
[] fTraces
;
62 * The set of traces that constitute the experiment
64 private boolean fInitialized
= false;
67 * The experiment bookmarks file
69 private IFile fBookmarksFile
;
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
76 * @param type the event type
77 * @param id the experiment id
78 * @param traces the experiment set of traces
80 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
81 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
);
85 * @param type the event type
86 * @param path the experiment path
87 * @param traces the experiment set of traces
88 * @param indexPageSize the experiment index page size
90 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
91 setCacheSize(indexPageSize
);
92 setStreamingInterval(0);
93 setIndexer(new TmfCheckpointIndexer(this, indexPageSize
));
96 super.initialize(null, path
, type
);
97 } catch (TmfTraceException e
) {
105 * Clears the experiment
108 public synchronized void dispose() {
110 // Clean up the index if applicable
111 if (getIndexer() != null) {
112 getIndexer().dispose();
115 if (fTraces
!= null) {
116 for (final ITmfTrace trace
: fTraces
) {
125 * @param signal the clear view signal
129 public void handleClearExperimentSignal(TmfClearExperimentSignal signal
) {
133 // ------------------------------------------------------------------------
134 // ITmfTrace - Initializers
135 // ------------------------------------------------------------------------
138 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
141 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
145 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
148 public boolean validate(final IProject project
, final String path
) {
152 // ------------------------------------------------------------------------
154 // ------------------------------------------------------------------------
157 * Get the list of traces. Handle with care...
159 * @return the experiment traces
161 public ITmfTrace
[] getTraces() {
166 * Returns the timestamp of the event at the requested index. If none,
169 * @param index the event index (rank)
170 * @return the corresponding event timestamp
172 public ITmfTimestamp
getTimestamp(final int index
) {
173 final ITmfContext context
= seekEvent(index
);
174 final ITmfEvent event
= getNext(context
);
176 return (event
!= null) ? event
.getTimestamp() : null;
180 * Set the file to be used for bookmarks on this experiment
182 * @param file the bookmarks file
184 public void setBookmarksFile(final IFile file
) {
185 fBookmarksFile
= file
;
189 * Get the file used for bookmarks on this experiment
191 * @return the bookmarks file or null if none is set
193 public IFile
getBookmarksFile() {
194 return fBookmarksFile
;
197 // ------------------------------------------------------------------------
198 // Request management
199 // ------------------------------------------------------------------------
205 public synchronized ITmfContext
armRequest(final ITmfRequest request
) {
207 // Make sure we have something to read from
208 if (fTraces
== null) {
212 ITmfTimestamp startTime
= request
.getTimeRange().getStartTime();
213 long startindex
= request
.getStartIndex();
214 if (!TmfTimestamp
.BIG_BANG
.equals(startTime
) && startindex
== 0) {
215 final ITmfContext context
= seekEvent(request
.getTimeRange().getStartTime());
216 request
.addEventFilter(new TmfBlockFilter(context
.getRank(), request
.getNbRequested()));
220 return seekEvent(request
.getStartIndex());
223 // ------------------------------------------------------------------------
224 // ITmfTrace trace positioning
225 // ------------------------------------------------------------------------
229 * Returns a brand new context based on the location provided and
230 * initializes the event queues
232 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
235 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
236 // Validate the location
237 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
238 return null; // Throw an exception?
240 // Make sure we have something to read from
241 if (fTraces
== null) {
245 // Create and populate the context's traces contexts
246 final TmfExperimentContext context
= new TmfExperimentContext(new ITmfContext
[fTraces
.length
]);
247 ITmfLocation
[] expLocations
= new ITmfLocation
[fTraces
.length
];
248 if (location
!= null) {
249 TmfExperimentLocation locations
= (TmfExperimentLocation
) location
;
251 ITmfLocation l
= locations
.getLocationInfo().getLocation(index
);
252 while (index
< expLocations
.length
&& l
!= null) {
253 expLocations
[index
] = l
;
254 l
= locations
.getLocationInfo().getLocation(++index
);
258 // Position the traces
259 for (int i
= 0; i
< fTraces
.length
; i
++) {
260 // Get the relevant trace attributes
261 final ITmfLocation trcLocation
= expLocations
[i
];
262 context
.getContexts()[i
] = fTraces
[i
].seekEvent(trcLocation
);
263 expLocations
[i
] = context
.getContexts()[i
].getLocation();
264 context
.getEvents()[i
] = fTraces
[i
].getNext(context
.getContexts()[i
]);
268 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(expLocations
)));
269 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
270 context
.setRank((location
== null) ?
0 : ITmfContext
.UNKNOWN_RANK
);
275 // ------------------------------------------------------------------------
276 // ITmfTrace - SeekEvent operations (returning a trace context)
277 // ------------------------------------------------------------------------
280 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
283 public ITmfContext
seekEvent(final double ratio
) {
284 final ITmfContext context
= seekEvent(Math
.round(ratio
* getNbEvents()));
289 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
292 public double getLocationRatio(final ITmfLocation location
) {
293 if (location
instanceof TmfExperimentLocation
) {
294 return (double) seekEvent(location
).getRank() / getNbEvents();
300 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
303 public ITmfLocation
getCurrentLocation() {
304 ITmfLocation
[] locations
= new ITmfLocation
[fTraces
.length
];
305 for (int i
= 0; i
< fTraces
.length
; i
++) {
306 locations
[i
] = fTraces
[i
].getCurrentLocation();
308 return new TmfExperimentLocation(new TmfLocationArray(locations
));
311 // ------------------------------------------------------------------------
312 // ITmfTrace trace positioning
313 // ------------------------------------------------------------------------
316 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
319 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
320 final ITmfContext savedContext
= context
.clone();
321 final ITmfEvent event
= getNext(savedContext
);
326 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
329 public synchronized ITmfEvent
getNext(ITmfContext context
) {
331 // Validate the context
332 if (!(context
instanceof TmfExperimentContext
)) {
333 return null; // Throw an exception?
336 // Make sure that we have something to read from
337 if (fTraces
== null) {
341 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
343 // If an event was consumed previously, first get the next one from that trace
344 final int lastTrace
= expContext
.getLastTrace();
345 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
346 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
347 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
348 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
351 // Scan the candidate events and identify the "next" trace to read from
352 int trace
= TmfExperimentContext
.NO_TRACE
;
353 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
354 for (int i
= 0; i
< fTraces
.length
; i
++) {
355 final ITmfEvent event
= expContext
.getEvents()[i
];
356 if (event
!= null && event
.getTimestamp() != null) {
357 final ITmfTimestamp otherTS
= event
.getTimestamp();
358 if (otherTS
.compareTo(timestamp
, true) < 0) {
365 ITmfEvent event
= null;
366 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
367 event
= expContext
.getEvents()[trace
];
369 updateAttributes(expContext
, event
.getTimestamp());
370 expContext
.increaseRank();
371 expContext
.setLastTrace(trace
);
372 final ITmfContext traceContext
= expContext
.getContexts()[trace
];
374 expContext
.setLocation(new TmfExperimentLocation(
375 (TmfExperimentLocation
) expContext
.getLocation(),
376 trace
, traceContext
.getLocation()));
386 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getInitialRangeOffset()
392 public ITmfTimestamp
getInitialRangeOffset() {
393 if ((fTraces
== null) || (fTraces
.length
== 0)) {
394 return super.getInitialRangeOffset();
397 ITmfTimestamp initTs
= TmfTimestamp
.BIG_CRUNCH
;
398 for (int i
= 0; i
< fTraces
.length
; i
++) {
399 ITmfTimestamp ts
= fTraces
[i
].getInitialRangeOffset();
400 if (ts
.compareTo(initTs
) < 0) {
408 * @see java.lang.Object#toString()
411 @SuppressWarnings("nls")
412 public String
toString() {
413 return "[TmfExperiment (" + getName() + ")]";
416 // ------------------------------------------------------------------------
418 // ------------------------------------------------------------------------
420 private synchronized void initializeStreamingMonitor() {
427 if (getStreamingInterval() == 0) {
428 final ITmfContext context
= seekEvent(0);
429 final ITmfEvent event
= getNext(context
);
434 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp(), TmfTimestamp
.BIG_CRUNCH
);
435 final TmfTraceRangeUpdatedSignal signal
= new TmfTraceRangeUpdatedSignal(this, this, timeRange
);
437 // Broadcast in separate thread to prevent deadlock
447 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
448 private ITmfTimestamp safeTimestamp
= null;
449 private ITmfTimestamp lastSafeTimestamp
= null;
450 private TmfTimeRange timeRange
= null;
454 while (!executorIsShutdown()) {
455 if (!getIndexer().isIndexing()) {
456 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
457 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
458 for (final ITmfTrace trace
: fTraces
) {
459 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
460 startTimestamp
= trace
.getStartTime();
462 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
463 endTimestamp
= trace
.getEndTime();
466 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
467 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
468 lastSafeTimestamp
= safeTimestamp
;
472 safeTimestamp
= endTimestamp
;
473 if (timeRange
!= null) {
474 final TmfTraceRangeUpdatedSignal signal
=
475 new TmfTraceRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
480 Thread
.sleep(getStreamingInterval());
481 } catch (final InterruptedException e
) {
491 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
494 public long getStreamingInterval() {
496 for (final ITmfTrace trace
: fTraces
) {
497 interval
= Math
.max(interval
, trace
.getStreamingInterval());
502 // ------------------------------------------------------------------------
504 // ------------------------------------------------------------------------
507 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#traceOpened(org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal)
511 public void traceOpened(TmfTraceOpenedSignal signal
) {
512 if (signal
.getTrace() == this) {
513 initializeStreamingMonitor();