1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson, École Polytechnique de Montréal
4 * All rights reserved. This program and the accompanying materials are made
5 * 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 * Matthew Khouzam - Initial API and implementation
11 * Patrick Tasse - Updated for removal of context clone
12 * Geneviève Bastien - Added the createTimestamp function
13 *******************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.core
.ctfadaptor
;
17 import java
.nio
.BufferOverflowException
;
18 import java
.nio
.ByteBuffer
;
19 import java
.util
.Collections
;
22 import org
.eclipse
.core
.resources
.IProject
;
23 import org
.eclipse
.core
.resources
.IResource
;
24 import org
.eclipse
.core
.runtime
.IStatus
;
25 import org
.eclipse
.core
.runtime
.Status
;
26 import org
.eclipse
.linuxtools
.ctf
.core
.event
.CTFClock
;
27 import org
.eclipse
.linuxtools
.ctf
.core
.event
.IEventDeclaration
;
28 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFReaderException
;
29 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFTrace
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFTraceReader
;
31 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Activator
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfContext
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfEventParser
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTraceProperties
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTrace
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfPersistentlyIndexable
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfTraceIndexer
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.TmfBTreeTraceIndexer
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.checkpoint
.ITmfCheckpoint
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.checkpoint
.TmfCheckpoint
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.ITmfLocation
;
48 * The CTf trace handler
51 * @author Matthew khouzam
53 public class CtfTmfTrace
extends TmfTrace
54 implements ITmfEventParser
, ITmfTraceProperties
, ITmfPersistentlyIndexable
{
56 // -------------------------------------------
58 // -------------------------------------------
60 * Default cache size for CTF traces
62 protected static final int DEFAULT_CACHE_SIZE
= 50000;
65 * The Ctf clock unique identifier field
67 private static final String CLOCK_HOST_PROPERTY
= "uuid"; //$NON-NLS-1$
69 // -------------------------------------------
71 // -------------------------------------------
73 /* Reference to the CTF Trace */
74 private CTFTrace fTrace
;
76 // -------------------------------------------
78 // -------------------------------------------
83 * The resource associated with this trace
85 * The path to the trace file
87 * The type of events that will be read from this trace
88 * @throws TmfTraceException
89 * If something went wrong while reading the trace
92 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> eventType
)
93 throws TmfTraceException
{
95 * Set the cache size. This has to be done before the call to super()
96 * because the super needs to know the cache size.
100 super.initTrace(resource
, path
, eventType
);
103 this.fTrace
= new CTFTrace(path
);
104 CtfIteratorManager
.addTrace(this);
106 /* Set the start and (current) end times for this trace */
107 ctx
= (CtfTmfContext
) seekEvent(0L);
108 CtfTmfEvent event
= getNext(ctx
);
109 if ((ctx
.getLocation().equals(CtfIterator
.NULL_LOCATION
)) || (ctx
.getCurrentEvent() == null)) {
110 /* Handle the case where the trace is empty */
111 this.setStartTime(TmfTimestamp
.BIG_BANG
);
113 final ITmfTimestamp curTime
= event
.getTimestamp();
114 this.setStartTime(curTime
);
115 this.setEndTime(curTime
);
118 } catch (final CTFReaderException e
) {
120 * If it failed at the init(), we can assume it's because the file
121 * was not found or was not recognized as a CTF trace. Throw into
122 * the new type of exception expected by the rest of TMF.
124 throw new TmfTraceException(e
.getMessage(), e
);
129 public synchronized void dispose() {
130 CtfIteratorManager
.removeTrace(this);
131 if (fTrace
!= null) {
145 * @return IStatus IStatus.error or Status.OK_STATUS
146 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(IProject, String)
150 public IStatus
validate(final IProject project
, final String path
) {
151 IStatus validTrace
= Status
.OK_STATUS
;
153 final CTFTrace temp
= new CTFTrace(path
);
154 if (!temp
.majorIsSet()) {
155 validTrace
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_MajorNotSet
);
157 CTFTraceReader ctfTraceReader
= new CTFTraceReader(temp
);
158 if (!ctfTraceReader
.hasMoreEvents()) {
159 // TODO: This will need an additional check when we support live traces
160 // because having no event is valid for a live trace
161 validTrace
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_NoEvent
);
163 ctfTraceReader
.dispose();
166 } catch (final CTFReaderException e
) {
167 validTrace
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_ReadingError
+": " + e
.toString()); //$NON-NLS-1$
168 } catch (final BufferOverflowException e
){
169 validTrace
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_ReadingError
+": " + Messages
.CtfTmfTrace_BufferOverflowErrorMessage
); //$NON-NLS-1$
176 * Method getCurrentLocation. This is not applicable in CTF
178 * @return null, since the trace has no knowledge of the current location
179 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
183 public ITmfLocation
getCurrentLocation() {
191 public double getLocationRatio(ITmfLocation location
) {
192 final CtfLocation curLocation
= (CtfLocation
) location
;
193 final CtfTmfContext context
= new CtfTmfContext(this);
194 context
.setLocation(curLocation
);
195 context
.seek(curLocation
.getLocationInfo());
196 final CtfLocationInfo currentTime
= ((CtfLocationInfo
) context
.getLocation().getLocationInfo());
197 final long startTime
= getIterator(this, context
).getStartTime();
198 final long endTime
= getIterator(this, context
).getEndTime();
199 return ((double) currentTime
.getTimestamp() - startTime
)
200 / (endTime
- startTime
);
208 * @return ITmfContext
212 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
213 CtfLocation currentLocation
= (CtfLocation
) location
;
214 CtfTmfContext context
= new CtfTmfContext(this);
215 if (fTrace
== null) {
216 context
.setLocation(null);
217 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
221 * The rank is set to 0 if the iterator seeks the beginning. If not, it
222 * will be set to UNKNOWN_RANK, since CTF traces don't support seeking
225 if (currentLocation
== null) {
226 currentLocation
= new CtfLocation(new CtfLocationInfo(0L, 0L));
229 if (currentLocation
.getLocationInfo() == CtfLocation
.INVALID_LOCATION
) {
230 currentLocation
= new CtfLocation(getEndTime().getValue() + 1, 0L);
232 context
.setLocation(currentLocation
);
233 if (location
== null) {
234 CtfTmfEvent event
= getIterator(this, context
).getCurrentEvent();
236 currentLocation
= new CtfLocation(event
.getTimestamp().getValue(), 0);
239 if (context
.getRank() != 0) {
240 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
246 public synchronized ITmfContext
seekEvent(double ratio
) {
247 CtfTmfContext context
= new CtfTmfContext(this);
248 if (fTrace
== null) {
249 context
.setLocation(null);
250 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
253 final long end
= this.getEndTime().getValue();
254 final long start
= this.getStartTime().getValue();
255 final long diff
= end
- start
;
256 final long ratioTs
= Math
.round(diff
* ratio
) + start
;
257 context
.seek(ratioTs
);
258 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
263 * Method readNextEvent.
267 * @return CtfTmfEvent
268 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getNext(ITmfContext)
271 public synchronized CtfTmfEvent
getNext(final ITmfContext context
) {
272 if (fTrace
== null) {
275 CtfTmfEvent event
= null;
276 if (context
instanceof CtfTmfContext
) {
277 if (context
.getLocation() == null || CtfLocation
.INVALID_LOCATION
.equals(context
.getLocation().getLocationInfo())) {
280 CtfTmfContext ctfContext
= (CtfTmfContext
) context
;
281 event
= ctfContext
.getCurrentEvent();
284 updateAttributes(context
, event
.getTimestamp());
285 ctfContext
.advance();
286 ctfContext
.increaseRank();
294 * gets the CTFtrace that this is wrapping
296 * @return the CTF trace
298 public CTFTrace
getCTFTrace() {
303 * Ctf traces have a clock with a unique uuid that will be used to identify
304 * the host. Traces with the same clock uuid will be known to have been made
305 * on the same machine.
307 * Note: uuid is an optional field, it may not be there for a clock.
310 public String
getHostId() {
311 CTFClock clock
= getCTFTrace().getClock();
313 String clockHost
= (String
) clock
.getProperty(CLOCK_HOST_PROPERTY
);
314 if (clockHost
!= null) {
318 return super.getHostId();
321 // -------------------------------------------
322 // ITmfTraceProperties
323 // -------------------------------------------
329 public Map
<String
, String
> getTraceProperties() {
330 return Collections
.unmodifiableMap(fTrace
.getEnvironment());
333 // -------------------------------------------
335 // -------------------------------------------
338 * gets the clock offset
340 * @return the clock offset in ns
342 public long getOffset() {
343 if (fTrace
!= null) {
344 return fTrace
.getOffset();
350 * Returns whether or not an event is in the metadata of the trace,
351 * therefore if it can possibly be in the trace. It does not verify whether
352 * or not the event is actually in the trace
355 * The name of the event to check
356 * @return Whether the event is in the metadata or not
359 public boolean hasEvent(final String eventName
) {
360 Map
<Long
, IEventDeclaration
> events
= fTrace
.getEvents(0L);
361 if (events
!= null) {
362 for (IEventDeclaration decl
: events
.values()) {
363 if (decl
.getName().equals(eventName
)) {
372 * Return whether all requested events are in the metadata
375 * The array of events to check for
376 * @return Whether all events are in the metadata
379 public boolean hasAllEvents(String
[] names
) {
380 for (String name
: names
) {
381 if (!hasEvent(name
)) {
389 * Returns whether the metadata contains at least one of the requested
393 * The array of event names of check for
394 * @return Whether one of the event is present in trace metadata
397 public boolean hasAtLeastOneOfEvents(String
[] names
) {
398 for (String name
: names
) {
399 if (hasEvent(name
)) {
406 // -------------------------------------------
408 // -------------------------------------------
411 public CtfTmfEvent
parseEvent(ITmfContext context
) {
412 CtfTmfEvent event
= null;
413 if (context
instanceof CtfTmfContext
) {
414 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
415 event
= getNext(tmpContext
);
421 * Sets the cache size for a CtfTmfTrace.
423 protected void setCacheSize() {
424 setCacheSize(DEFAULT_CACHE_SIZE
);
427 // -------------------------------------------
429 // -------------------------------------------
431 private static CtfIterator
getIterator(CtfTmfTrace trace
, CtfTmfContext context
) {
432 return CtfIteratorManager
.getIterator(trace
, context
);
436 * Get an iterator to the trace
438 * @return an iterator to the trace
441 public CtfIterator
createIterator() {
443 return new CtfIterator(this);
444 } catch (CTFReaderException e
) {
445 Activator
.logError(e
.getMessage(), e
);
450 // ------------------------------------------------------------------------
451 // Timestamp transformation functions
452 // ------------------------------------------------------------------------
458 public CtfTmfTimestamp
createTimestamp(long ts
) {
459 return new CtfTmfTimestamp(getTimestampTransform().transform(ts
));
462 private static int fCheckpointSize
= -1;
465 public synchronized int getCheckpointSize() {
466 if (fCheckpointSize
== -1) {
467 TmfCheckpoint c
= new TmfCheckpoint(new CtfTmfTimestamp(0), new CtfLocation(0, 0), 0);
468 ByteBuffer b
= ByteBuffer
.allocate(ITmfCheckpoint
.MAX_SERIALIZE_SIZE
);
471 fCheckpointSize
= b
.position();
474 return fCheckpointSize
;
478 protected ITmfTraceIndexer
createIndexer(int interval
) {
479 return new TmfBTreeTraceIndexer(this, interval
);
483 public ITmfLocation
restoreLocation(ByteBuffer bufferIn
) {
484 return new CtfLocation(bufferIn
);