1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 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
.tracecompass
.tmf
.ctf
.core
;
17 import java
.nio
.BufferOverflowException
;
18 import java
.nio
.ByteBuffer
;
19 import java
.util
.ArrayList
;
20 import java
.util
.HashMap
;
21 import java
.util
.List
;
25 import org
.eclipse
.core
.resources
.IProject
;
26 import org
.eclipse
.core
.resources
.IResource
;
27 import org
.eclipse
.core
.runtime
.CoreException
;
28 import org
.eclipse
.core
.runtime
.IStatus
;
29 import org
.eclipse
.core
.runtime
.Status
;
30 import org
.eclipse
.linuxtools
.ctf
.core
.event
.CTFClock
;
31 import org
.eclipse
.linuxtools
.ctf
.core
.event
.IEventDeclaration
;
32 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFReaderException
;
33 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFTrace
;
34 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFTraceReader
;
35 import org
.eclipse
.tracecompass
.internal
.tmf
.ctf
.core
.Activator
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventField
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEventType
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventField
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventTypeManager
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.exceptions
.TmfTraceException
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfContext
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfEventParser
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTraceProperties
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTraceWithPreDefinedEvents
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTrace
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TraceValidationStatus
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.ITmfPersistentlyIndexable
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.ITmfTraceIndexer
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.TmfBTreeTraceIndexer
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.checkpoint
.ITmfCheckpoint
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.checkpoint
.TmfCheckpoint
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.location
.ITmfLocation
;
57 import com
.google
.common
.collect
.ImmutableSet
;
60 * The CTf trace handler
63 * @author Matthew khouzam
65 public class CtfTmfTrace
extends TmfTrace
66 implements ITmfEventParser
, ITmfTraceProperties
, ITmfPersistentlyIndexable
,
67 ITmfTraceWithPreDefinedEvents
, AutoCloseable
{
69 // -------------------------------------------
71 // -------------------------------------------
73 * Default cache size for CTF traces
75 protected static final int DEFAULT_CACHE_SIZE
= 50000;
78 * The Ctf clock unique identifier field
80 private static final String CLOCK_HOST_PROPERTY
= "uuid"; //$NON-NLS-1$
81 private static final int CONFIDENCE
= 10;
83 // -------------------------------------------
85 // -------------------------------------------
87 /* Reference to the CTF Trace */
88 private CTFTrace fTrace
;
90 // -------------------------------------------
92 // -------------------------------------------
97 * The resource associated with this trace
99 * The path to the trace file
101 * The type of events that will be read from this trace
102 * @throws TmfTraceException
103 * If something went wrong while reading the trace
106 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> eventType
)
107 throws TmfTraceException
{
109 * Set the cache size. This has to be done before the call to super()
110 * because the super needs to know the cache size.
114 super.initTrace(resource
, path
, eventType
);
117 this.fTrace
= new CTFTrace(path
);
118 CtfIteratorManager
.addTrace(this);
120 /* Set the start and (current) end times for this trace */
121 ctx
= (CtfTmfContext
) seekEvent(0L);
122 CtfTmfEvent event
= getNext(ctx
);
123 if ((ctx
.getLocation().equals(CtfIterator
.NULL_LOCATION
)) || (ctx
.getCurrentEvent() == null)) {
124 /* Handle the case where the trace is empty */
125 this.setStartTime(TmfTimestamp
.BIG_BANG
);
127 final ITmfTimestamp curTime
= event
.getTimestamp();
128 this.setStartTime(curTime
);
129 this.setEndTime(curTime
);
132 * Register every event type. When you call getType, it will
133 * register a trace to that type in the TmfEventTypeManager
135 try (CtfIterator iter
= CtfIteratorManager
.getIterator(this, ctx
)) {
136 for (IEventDeclaration ied
: iter
.getEventDeclarations()) {
137 CtfTmfEventType ctfTmfEventType
= CtfTmfEventType
.get(this, ied
.getName());
138 if (ctfTmfEventType
== null) {
139 List
<ITmfEventField
> content
= new ArrayList
<>();
140 /* Should only return null the first time */
141 for (String fieldName
: ied
.getFields().getFieldsList()) {
142 content
.add(new TmfEventField(fieldName
, null, null));
144 ITmfEventField contentTree
= new TmfEventField(
145 ITmfEventField
.ROOT_FIELD_ID
,
147 content
.toArray(new ITmfEventField
[content
.size()])
150 ctfTmfEventType
= new CtfTmfEventType(ied
.getName(), this, contentTree
);
154 } catch (final CTFReaderException e
) {
156 * If it failed at the init(), we can assume it's because the file
157 * was not found or was not recognized as a CTF trace. Throw into
158 * the new type of exception expected by the rest of TMF.
160 throw new TmfTraceException(e
.getMessage(), e
);
165 public void close() {
170 public synchronized void dispose() {
171 CtfIteratorManager
.removeTrace(this);
172 if (fTrace
!= null) {
182 * The default implementation sets the confidence to 10 if the trace is a
186 public IStatus
validate(final IProject project
, final String path
) {
187 IStatus status
= new TraceValidationStatus(CONFIDENCE
, Activator
.PLUGIN_ID
);
188 try (final CTFTrace temp
= new CTFTrace(path
);) {
189 if (!temp
.majorIsSet()) {
190 status
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_MajorNotSet
);
192 try (CTFTraceReader ctfTraceReader
= new CTFTraceReader(temp
);) {
193 if (!ctfTraceReader
.hasMoreEvents()) {
194 // TODO: This will need an additional check when we
195 // support live traces
196 // because having no event is valid for a live trace
197 status
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_NoEvent
);
201 } catch (final CTFReaderException e
) {
202 status
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_ReadingError
+ ": " + e
.toString()); //$NON-NLS-1$
203 } catch (final BufferOverflowException e
) {
204 status
= new Status(IStatus
.ERROR
, Activator
.PLUGIN_ID
, Messages
.CtfTmfTrace_ReadingError
+ ": " + Messages
.CtfTmfTrace_BufferOverflowErrorMessage
); //$NON-NLS-1$
211 * Method getCurrentLocation. This is not applicable in CTF
213 * @return null, since the trace has no knowledge of the current location
214 * @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getCurrentLocation()
218 public ITmfLocation
getCurrentLocation() {
226 public double getLocationRatio(ITmfLocation location
) {
227 final CtfLocation curLocation
= (CtfLocation
) location
;
228 final CtfTmfContext context
= new CtfTmfContext(this);
229 context
.setLocation(curLocation
);
230 context
.seek(curLocation
.getLocationInfo());
231 final CtfLocationInfo currentTime
= ((CtfLocationInfo
) context
.getLocation().getLocationInfo());
232 final long startTime
= getIterator(this, context
).getStartTime();
233 final long endTime
= getIterator(this, context
).getEndTime();
234 return ((double) currentTime
.getTimestamp() - startTime
)
235 / (endTime
- startTime
);
243 * @return ITmfContext
247 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
248 CtfLocation currentLocation
= (CtfLocation
) location
;
249 CtfTmfContext context
= new CtfTmfContext(this);
250 if (fTrace
== null) {
251 context
.setLocation(null);
252 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
256 * The rank is set to 0 if the iterator seeks the beginning. If not, it
257 * will be set to UNKNOWN_RANK, since CTF traces don't support seeking
260 if (currentLocation
== null) {
261 currentLocation
= new CtfLocation(new CtfLocationInfo(0L, 0L));
264 if (currentLocation
.getLocationInfo() == CtfLocation
.INVALID_LOCATION
) {
265 currentLocation
= new CtfLocation(getCTFTrace().getCurrentEndTime() + 1, 0L);
267 context
.setLocation(currentLocation
);
268 if (location
== null) {
269 long timestamp
= getIterator(this, context
).getCurrentTimestamp();
270 currentLocation
= new CtfLocation(timestamp
, 0);
272 if (context
.getRank() != 0) {
273 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
279 public synchronized ITmfContext
seekEvent(double ratio
) {
280 CtfTmfContext context
= new CtfTmfContext(this);
281 if (fTrace
== null) {
282 context
.setLocation(null);
283 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
286 final long end
= getCTFTrace().getCurrentEndTime();
287 final long start
= getCTFTrace().getCurrentStartTime();
288 final long diff
= end
- start
;
289 final long ratioTs
= Math
.round(diff
* ratio
) + start
;
290 context
.seek(ratioTs
);
291 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
296 * Method readNextEvent.
300 * @return CtfTmfEvent
301 * @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getNext(ITmfContext)
304 public synchronized CtfTmfEvent
getNext(final ITmfContext context
) {
305 if (fTrace
== null) {
308 CtfTmfEvent event
= null;
309 if (context
instanceof CtfTmfContext
) {
310 if (context
.getLocation() == null || CtfLocation
.INVALID_LOCATION
.equals(context
.getLocation().getLocationInfo())) {
313 CtfTmfContext ctfContext
= (CtfTmfContext
) context
;
314 event
= ctfContext
.getCurrentEvent();
317 updateAttributes(context
, event
.getTimestamp());
318 ctfContext
.advance();
319 ctfContext
.increaseRank();
327 * gets the CTFtrace that this is wrapping
329 * @return the CTF trace
331 public CTFTrace
getCTFTrace() {
336 * Ctf traces have a clock with a unique uuid that will be used to identify
337 * the host. Traces with the same clock uuid will be known to have been made
338 * on the same machine.
340 * Note: uuid is an optional field, it may not be there for a clock.
343 public String
getHostId() {
344 CTFClock clock
= getCTFTrace().getClock();
346 String clockHost
= (String
) clock
.getProperty(CLOCK_HOST_PROPERTY
);
347 if (clockHost
!= null) {
351 return super.getHostId();
354 // -------------------------------------------
355 // ITmfTraceProperties
356 // -------------------------------------------
362 public Map
<String
, String
> getTraceProperties() {
363 Map
<String
, String
> properties
= new HashMap
<>();
364 properties
.putAll(fTrace
.getEnvironment());
365 properties
.put(Messages
.CtfTmfTrace_HostID
, getHostId());
369 // -------------------------------------------
371 // -------------------------------------------
374 * gets the clock offset
376 * @return the clock offset in ns
378 public long getOffset() {
379 if (fTrace
!= null) {
380 return fTrace
.getOffset();
386 * Gets the list of declared events
391 public Set
<ITmfEventType
> getContainedEventTypes() {
392 TmfEventTypeManager instance
= TmfEventTypeManager
.getInstance();
393 Set
<ITmfEventType
> eventTypes
= instance
.getTypes(CtfTmfEventType
.computeContextName(this));
394 return ImmutableSet
.copyOf(eventTypes
);
397 // -------------------------------------------
399 // -------------------------------------------
402 public CtfTmfEvent
parseEvent(ITmfContext context
) {
403 CtfTmfEvent event
= null;
404 if (context
instanceof CtfTmfContext
) {
405 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
406 event
= getNext(tmpContext
);
412 * Sets the cache size for a CtfTmfTrace.
414 protected void setCacheSize() {
415 setCacheSize(DEFAULT_CACHE_SIZE
);
418 // -------------------------------------------
420 // -------------------------------------------
422 private static CtfIterator
getIterator(CtfTmfTrace trace
, CtfTmfContext context
) {
423 return CtfIteratorManager
.getIterator(trace
, context
);
427 * Get an iterator to the trace
429 * @return an iterator to the trace
432 public CtfIterator
createIterator() {
434 return new CtfIterator(this);
435 } catch (CTFReaderException e
) {
436 Activator
.getDefault().logError(e
.getMessage(), e
);
441 // ------------------------------------------------------------------------
442 // Timestamp transformation functions
443 // ------------------------------------------------------------------------
449 public CtfTmfTimestamp
createTimestamp(long ts
) {
450 return new CtfTmfTimestamp(getTimestampTransform().transform(ts
));
453 private static int fCheckpointSize
= -1;
459 public synchronized int getCheckpointSize() {
460 if (fCheckpointSize
== -1) {
461 TmfCheckpoint c
= new TmfCheckpoint(new CtfTmfTimestamp(0), new CtfLocation(0, 0), 0);
462 ByteBuffer b
= ByteBuffer
.allocate(ITmfCheckpoint
.MAX_SERIALIZE_SIZE
);
465 fCheckpointSize
= b
.position();
468 return fCheckpointSize
;
472 protected ITmfTraceIndexer
createIndexer(int interval
) {
473 return new TmfBTreeTraceIndexer(this, interval
);
480 public ITmfLocation
restoreLocation(ByteBuffer bufferIn
) {
481 return new CtfLocation(bufferIn
);
485 public boolean isComplete() {
486 if (getResource() == null) {
492 String sessionName
= null;
494 host
= getResource().getPersistentProperty(CtfConstants
.LIVE_HOST
);
495 port
= getResource().getPersistentProperty(CtfConstants
.LIVE_PORT
);
496 sessionName
= getResource().getPersistentProperty(CtfConstants
.LIVE_SESSION_NAME
);
497 } catch (CoreException e
) {
498 Activator
.getDefault().logError(e
.getMessage(), e
);
499 // Something happened to the resource, assume we won't get any more data from it
502 return host
== null || port
== null || sessionName
== null;
506 public void setComplete(final boolean isComplete
) {
507 super.setComplete(isComplete
);
510 getResource().setPersistentProperty(CtfConstants
.LIVE_HOST
, null);
511 getResource().setPersistentProperty(CtfConstants
.LIVE_PORT
, null);
512 getResource().setPersistentProperty(CtfConstants
.LIVE_SESSION_NAME
, null);
514 } catch (CoreException e
) {
515 Activator
.getDefault().logError(e
.getMessage(), e
);