blob: 4d591ca4bf6934e8a2d0372663ca4faad7e77616 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2017 Ericsson, École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Matthew Khouzam - Initial API and implementation
* Patrick Tasse - Updated for removal of context clone
* Geneviève Bastien - Added the createTimestamp function
*******************************************************************************/
package org.eclipse.tracecompass.tmf.ctf.core.trace;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.core.event.CTFCallsite;
import org.eclipse.tracecompass.ctf.core.event.CTFClock;
import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration;
import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
import org.eclipse.tracecompass.ctf.core.trace.CTFStreamInput;
import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
import org.eclipse.tracecompass.ctf.core.trace.CTFTraceReader;
import org.eclipse.tracecompass.ctf.core.trace.CTFTraceWriter;
import org.eclipse.tracecompass.ctf.core.trace.ICTFStream;
import org.eclipse.tracecompass.ctf.core.trace.Metadata;
import org.eclipse.tracecompass.internal.tmf.ctf.core.Activator;
import org.eclipse.tracecompass.internal.tmf.ctf.core.event.aspect.CtfEventContextAspect;
import org.eclipse.tracecompass.internal.tmf.ctf.core.event.aspect.CtfPacketContextAspect;
import org.eclipse.tracecompass.internal.tmf.ctf.core.event.aspect.CtfPacketHeaderAspect;
import org.eclipse.tracecompass.internal.tmf.ctf.core.event.aspect.CtfStreamContextAspect;
import org.eclipse.tracecompass.internal.tmf.ctf.core.trace.iterator.CtfIterator;
import org.eclipse.tracecompass.internal.tmf.ctf.core.trace.iterator.CtfIteratorManager;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
import org.eclipse.tracecompass.tmf.core.event.aspect.TmfBaseAspects;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
import org.eclipse.tracecompass.tmf.core.project.model.ITmfPropertiesProvider;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.core.trace.ICyclesConverter;
import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceKnownSize;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceWithPreDefinedEvents;
import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
import org.eclipse.tracecompass.tmf.core.trace.trim.ITmfTrimmableTrace;
import org.eclipse.tracecompass.tmf.ctf.core.CtfConstants;
import org.eclipse.tracecompass.tmf.ctf.core.context.CtfLocation;
import org.eclipse.tracecompass.tmf.ctf.core.context.CtfLocationInfo;
import org.eclipse.tracecompass.tmf.ctf.core.context.CtfTmfContext;
import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEvent;
import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEventFactory;
import org.eclipse.tracecompass.tmf.ctf.core.event.CtfTmfEventType;
import org.eclipse.tracecompass.tmf.ctf.core.event.aspect.CtfChannelAspect;
import org.eclipse.tracecompass.tmf.ctf.core.event.aspect.CtfCpuAspect;
import org.eclipse.tracecompass.tmf.ctf.core.event.lookup.CtfTmfCallsite;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* The CTf trace handler
*
* @version 1.0
* @author Matthew khouzam
*/
public class CtfTmfTrace extends TmfTrace
implements ITmfPropertiesProvider, ITmfPersistentlyIndexable,
ITmfTraceWithPreDefinedEvents, ITmfTraceKnownSize, ICyclesConverter, ITmfTrimmableTrace {
// -------------------------------------------
// Constants
// -------------------------------------------
/**
* Clock offset property
*
* @since 1.2
*/
public static final String CLOCK_OFFSET = "clock_offset"; //$NON-NLS-1$
/**
* Default cache size for CTF traces
*/
protected static final int DEFAULT_CACHE_SIZE = 50000;
/**
* Event aspects available for all CTF traces
*
* @since 1.0
*/
protected static final @NonNull Collection<@NonNull ITmfEventAspect<?>> CTF_ASPECTS = ImmutableList.of(
TmfBaseAspects.getTimestampAspect(),
new CtfChannelAspect(),
new CtfCpuAspect(),
TmfBaseAspects.getEventTypeAspect(),
TmfBaseAspects.getContentsAspect(),
CtfPacketHeaderAspect.getInstance(),
CtfPacketContextAspect.getInstance(),
CtfStreamContextAspect.getInstance(),
CtfEventContextAspect.getInstance());
/**
* The Ctf clock unique identifier field
*/
private static final String CLOCK_HOST_PROPERTY = "uuid"; //$NON-NLS-1$
private static final int CONFIDENCE = 10;
private static final int MIN_CONFIDENCE = 1;
/**
* This is a reduction factor to avoid overflows.
*/
private static final long REDUCTION_FACTOR = 4096;
/**
* Average CTF event size, used to estimate the trace size. (Inspired by
* empirical observations with LTTng kernel traces, to avoid hanging at 100% for
* too long)
*
* TODO: Find a more suitable approximation, perhaps per concrete trace type or
* per trace directly with the metadata
*/
private static final int CTF_AVG_EVENT_SIZE = 16;
// -------------------------------------------
// Fields
// -------------------------------------------
private final Map<@NonNull String, @NonNull CtfTmfEventType> fContainedEventTypes = Collections.synchronizedMap(new HashMap<>());
private final CtfIteratorManager fIteratorManager = new CtfIteratorManager(this);
private final @NonNull CtfTmfEventFactory fEventFactory;
/** Reference to the CTF Trace */
private CTFTrace fTrace;
private UUID fUUID;
// -------------------------------------------
// Constructor
// -------------------------------------------
/**
* Default constructor
*/
public CtfTmfTrace() {
this(CtfTmfEventFactory.instance());
}
/**
* Constructor for sub-classes to specify their own event factory.
*
* @param eventFactory
* The event factory to use to generate trace events
* @since 2.0
*/
protected CtfTmfTrace(@NonNull CtfTmfEventFactory eventFactory) {
super();
fEventFactory = eventFactory;
}
// -------------------------------------------
// TmfTrace Overrides
// -------------------------------------------
/**
* Method initTrace.
*
* @param resource
* The resource associated with this trace
* @param path
* The path to the trace file
* @param eventType
* The type of events that will be read from this trace
* @throws TmfTraceException
* If something went wrong while reading the trace
*/
@Override
public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> eventType)
throws TmfTraceException {
/*
* Set the cache size. This has to be done before the call to super() because
* the super needs to know the cache size.
*/
setCacheSize();
super.initTrace(resource, path, eventType);
try {
this.fTrace = new CTFTrace(path);
CtfTmfContext ctx;
/* Set the start and (current) end times for this trace */
ctx = (CtfTmfContext) seekEvent(0L);
CtfTmfEvent event = getNext(ctx);
if ((ctx.getLocation().equals(CtfIterator.NULL_LOCATION)) || (ctx.getCurrentEvent() == null)) {
/* Handle the case where the trace is empty */
this.setStartTime(TmfTimestamp.BIG_BANG);
} else {
final ITmfTimestamp curTime = event.getTimestamp();
this.setStartTime(curTime);
this.setEndTime(curTime);
}
/*
* Register every event type. When you call getType, it will register a trace to
* that type in the TmfEventTypeManager
*/
try (CtfIterator iter = fIteratorManager.getIterator(ctx)) {
if (iter == null) {
throw new TmfTraceException("Failed to get CTF Iterator for path " + path); //$NON-NLS-1$
}
Set<@NonNull ITmfEventField> streamContextNames = new HashSet<>();
for (IEventDeclaration ied : iter.getEventDeclarations()) {
CtfTmfEventType ctfTmfEventType = fContainedEventTypes.get(ied.getName());
if (ctfTmfEventType == null) {
List<ITmfEventField> content = new ArrayList<>();
/* Should only return null the first time */
final StructDeclaration fields = ied.getFields();
if (fields != null) {
for (String fieldName : fields.getFieldsList()) {
content.add(new TmfEventField(checkNotNull(fieldName), null, null));
}
}
/* Add stream contexts */
final StructDeclaration streamContexts = ied.getStream().getEventContextDecl();
if (streamContextNames.isEmpty()) {
if (streamContexts != null) {
for (String fieldName : streamContexts.getFieldsList()) {
streamContextNames.add(new TmfEventField(checkNotNull(CtfConstants.CONTEXT_FIELD_PREFIX + fieldName), null, null));
}
}
}
content.addAll(streamContextNames);
if (!content.isEmpty()) {
ITmfEventField contentTree = new TmfEventField(
ITmfEventField.ROOT_FIELD_ID,
null,
content.toArray(new ITmfEventField[content.size()]));
ctfTmfEventType = new CtfTmfEventType(checkNotNull(ied.getName()), contentTree);
fContainedEventTypes.put(ctfTmfEventType.getName(), ctfTmfEventType);
}
}
}
}
ctx.dispose();
fUUID = fTrace.getUUID();
} catch (final CTFException e) {
/*
* If it failed at the init(), we can assume it's because the file was not found
* or was not recognized as a CTF trace. Throw into the new type of exception
* expected by the rest of TMF.
*/
throw new TmfTraceException(e.getMessage(), e);
}
}
@Override
public synchronized void dispose() {
fIteratorManager.dispose();
fContainedEventTypes.clear();
if (fTrace != null) {
fTrace = null;
}
super.dispose();
}
/**
* {@inheritDoc}
* <p>
* The default implementation of a CTF trace.
*
* Firstly a weak validation of the metadata is done to determine if the path is
* actually for a CTF trace. After that a full validation is done.
*
* If the weak and full validation are successful the confidence is set to 10.
*
* If the weak validation was successful, but the full validation fails a
* TraceValidationStatus with severity warning and confidence of 1 is returned.
*
* If both weak and full validation fails an error status is returned.
*/
@Override
public IStatus validate(final IProject project, final String path) {
boolean isMetadataFile = false;
String pluginId = Activator.PLUGIN_ID;
try {
isMetadataFile = Metadata.preValidate(path);
} catch (final CTFException e) {
return new Status(IStatus.ERROR, pluginId, Messages.CtfTmfTrace_ReadingError + ": " + e.toString(), e); //$NON-NLS-1$
}
if (isMetadataFile) {
// Trace is pre-validated, continue will full validation
try {
final CTFTrace trace = new CTFTrace(path);
if (!trace.majorIsSet()) {
if (isMetadataFile) {
return new TraceValidationStatus(MIN_CONFIDENCE, IStatus.WARNING, pluginId, Messages.CtfTmfTrace_MajorNotSet, null);
}
return new Status(IStatus.ERROR, pluginId, Messages.CtfTmfTrace_MajorNotSet);
}
// Validate using reader initialization
try (CTFTraceReader ctfTraceReader = new CTFTraceReader(trace)) {
// do nothing
}
// Get contained event names
Collection<String> eventNames = new HashSet<>();
for (ICTFStream stream : trace.getStreams()) {
for (IEventDeclaration ed : trace.getEventDeclarations(stream.getId())) {
if (ed != null) {
eventNames.add(ed.getName());
}
}
}
// Trace is validated, return with confidence
return new CtfTraceValidationStatus(CONFIDENCE, pluginId, trace.getEnvironment(), eventNames);
} catch (final CTFException | BufferOverflowException e) {
// return warning since it's a CTF trace but with errors in it
return new TraceValidationStatus(MIN_CONFIDENCE, IStatus.WARNING, pluginId, Messages.CtfTmfTrace_ReadingError + ": " + e.toString(), e); //$NON-NLS-1$
}
}
return new Status(IStatus.ERROR, pluginId, Messages.CtfTmfTrace_ReadingError);
}
@Override
public Iterable<ITmfEventAspect<?>> getEventAspects() {
return CTF_ASPECTS;
}
/**
* Method getCurrentLocation. This is not applicable in CTF
*
* @return null, since the trace has no knowledge of the current location
* @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getCurrentLocation()
*/
@Override
public ITmfLocation getCurrentLocation() {
return null;
}
@Override
public double getLocationRatio(ITmfLocation location) {
final CtfLocation curLocation = (CtfLocation) location;
final long startTime = getStartTime().getValue();
final double diff = curLocation.getLocationInfo().getTimestamp() - startTime;
final double total = getEndTime().getValue() - startTime;
return Math.max(0.0, Math.min(1.0, diff / total));
}
/**
* Method seekEvent.
*
* @param location
* ITmfLocation<?>
* @return ITmfContext
*/
@Override
public synchronized ITmfContext seekEvent(final ITmfLocation location) {
CtfLocation currentLocation = (CtfLocation) location;
CtfTmfContext context = new CtfTmfContext(this);
if (fTrace == null) {
context.setLocation(null);
context.setRank(ITmfContext.UNKNOWN_RANK);
return context;
}
/*
* The rank is set to 0 if the iterator seeks the beginning. If not, it will be
* set to UNKNOWN_RANK, since CTF traces don't support seeking by rank for now.
*/
if (currentLocation == null) {
currentLocation = new CtfLocation(new CtfLocationInfo(0L, 0L));
context.setRank(0);
} else {
context.setRank(ITmfContext.UNKNOWN_RANK);
}
/* This will seek and update the location after the seek */
context.setLocation(currentLocation);
return context;
}
@Override
public synchronized ITmfContext seekEvent(double ratio) {
CtfTmfContext context = new CtfTmfContext(this);
if (fTrace == null) {
context.setLocation(null);
context.setRank(ITmfContext.UNKNOWN_RANK);
return context;
}
final long end = getEndTime().getValue();
final long start = getStartTime().getValue();
final long diff = end - start;
final long ratioTs = Math.round(diff * ratio) + start;
context.seek(ratioTs);
context.setRank(ITmfContext.UNKNOWN_RANK);
return context;
}
/**
* Method readNextEvent.
*
* @param context
* ITmfContext
* @return CtfTmfEvent
* @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getNext(ITmfContext)
*/
@Override
public synchronized CtfTmfEvent getNext(final ITmfContext context) {
if (fTrace == null) {
return null;
}
CtfTmfEvent event = null;
if (context instanceof CtfTmfContext) {
if (context.getLocation() == null || CtfLocation.INVALID_LOCATION.equals(context.getLocation().getLocationInfo())) {
return null;
}
CtfTmfContext ctfContext = (CtfTmfContext) context;
event = ctfContext.getCurrentEvent();
if (event != null) {
updateAttributes(context, event);
ctfContext.advance();
ctfContext.increaseRank();
}
}
return event;
}
/**
* Ctf traces have a clock with a unique uuid that will be used to identify the
* host. Traces with the same clock uuid will be known to have been made on the
* same machine.
*
* Note: uuid is an optional field, it may not be there for a clock.
*/
@Override
public String getHostId() {
CTFTrace trace = fTrace;
if (trace != null) {
CTFClock clock = trace.getClock();
if (clock != null) {
String clockHost = (String) clock.getProperty(CLOCK_HOST_PROPERTY);
if (clockHost != null) {
return clockHost;
}
}
}
return super.getHostId();
}
/**
* Get the first callsite that matches the event name
*
* @param eventName
* The event name to look for
* @return The best callsite candidate
* @since 3.0
*/
public @Nullable CtfTmfCallsite getCallsite(String eventName) {
CTFTrace trace = fTrace;
if (trace != null) {
for (ICTFStream stream : fTrace.getStreams()) {
for (IEventDeclaration eventDeclaration : stream.getEventDeclarations()) {
if (eventDeclaration != null && Objects.equals(eventDeclaration.getName(), eventName) &&
!eventDeclaration.getCallsites().isEmpty()) {
return new CtfTmfCallsite(eventDeclaration.getCallsites().get(0));
}
}
}
}
return null;
}
/**
* Get the closest matching callsite for given event name and instruction
* pointer
*
* @param eventName
* The event name
* @param ip
* The instruction pointer
* @return The closest matching callsite
* @since 3.0
*/
public @Nullable CtfTmfCallsite getCallsite(String eventName, long ip) {
CtfTmfCallsite callsite = null;
CTFTrace trace = fTrace;
if (trace != null) {
for (ICTFStream stream : trace.getStreams()) {
for (IEventDeclaration eventDeclaration : stream.getEventDeclarations()) {
if (eventDeclaration != null && Objects.equals(eventDeclaration.getName(), eventName)) {
for (CTFCallsite cs : eventDeclaration.getCallsites()) {
if (cs.getIp() >= ip && (callsite == null || cs.getIp() < callsite.getIntructionPointer())) {
callsite = new CtfTmfCallsite(cs);
}
}
}
}
}
}
return callsite;
}
/**
* Get the CTF environment variables defined in this CTF trace, in <name, value>
* form. This comes from the trace's CTF metadata.
*
* @return The CTF environment
*/
public Map<String, String> getEnvironment() {
CTFTrace trace = fTrace;
if (trace == null) {
return Collections.emptyMap();
}
return trace.getEnvironment();
}
/**
* @since 3.0
*/
@Override
public UUID getUUID() {
UUID uuid = fUUID;
return uuid == null ? super.getUUID() : uuid;
}
// -------------------------------------------
// ITmfPropertiesProvider
// -------------------------------------------
/**
* @since 2.0
*/
@Override
public Map<String, String> getProperties() {
Map<String, String> properties = new HashMap<>();
CTFTrace trace = fTrace;
if (trace == null) {
return properties;
}
properties.putAll(trace.getEnvironment());
properties.put(CLOCK_OFFSET, Long.toUnsignedString(trace.getOffset()));
properties.put(Messages.CtfTmfTrace_HostID, getHostId());
return properties;
}
// -------------------------------------------
// Clocks
// -------------------------------------------
/**
* Gets the clock offset with respect to POSIX.1 Epoch in cycles
*
* @return the clock offset with respect to POSIX.1 Epoch in cycles
*/
public long getOffset() {
CTFTrace trace = fTrace;
if (trace != null) {
return trace.getOffset();
}
return 0;
}
/**
* Convert a CTF timestamp in CPU cycles to its equivalent in nanoseconds for
* this trace.
*
* @param cycles
* The timestamp in cycles, relative to the clock offset
* @return The timestamp in nanoseconds, relative to POSIX.1 Epoch
*/
public long timestampCyclesToNanos(long cycles) {
CTFTrace trace = fTrace;
if (trace != null) {
return trace.timestampCyclesToNanos(cycles);
}
return 0;
}
/**
* Convert a CTF timestamp in nanoseconds to its equivalent in CPU cycles for
* this trace.
*
* @param nanos
* The timestamp in nanoseconds, relative to POSIX.1 Epoch
* @return The timestamp in cycles, relative to the clock offset
*/
public long timestampNanoToCycles(long nanos) {
CTFTrace trace = fTrace;
if (trace != null) {
return trace.timestampNanoToCycles(nanos);
}
return 0;
}
/**
* Gets the list of declared events
*/
@Override
public Set<@NonNull CtfTmfEventType> getContainedEventTypes() {
return ImmutableSet.copyOf(fContainedEventTypes.values());
}
/**
* Register an event type to this trace.
*
* Public visibility so that {@link CtfTmfEvent#getType} can call it.
*
* FIXME This could probably be made cleaner?
*
* @param eventType
* The event type to register
*/
public void registerEventType(CtfTmfEventType eventType) {
fContainedEventTypes.put(eventType.getName(), eventType);
}
// -------------------------------------------
// Parser
// -------------------------------------------
@Override
public CtfTmfEvent parseEvent(ITmfContext context) {
CtfTmfEvent event = null;
if (context instanceof CtfTmfContext) {
final ITmfContext tmpContext = seekEvent(context.getLocation());
event = getNext(tmpContext);
}
return event;
}
/**
* Sets the cache size for a CtfTmfTrace.
*/
protected void setCacheSize() {
setCacheSize(DEFAULT_CACHE_SIZE);
}
// -------------------------------------------
// CtfIterator factory methods
// -------------------------------------------
/**
* Get the event factory for this trace to generate new events for it.
*
* @return The event factory
* @since 2.0
*/
public @NonNull CtfTmfEventFactory getEventFactory() {
return fEventFactory;
}
/**
* Get an iterator to the trace
*
* @return an iterator to the trace
*/
public ITmfContext createIterator() {
try {
return new CtfIterator(fTrace, this);
} catch (CTFException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
return null;
}
/**
* Get an iterator to the trace, , which will initially point to the given
* location/rank.
*
* @param ctfLocationData
* The initial timestamp the iterator will be pointing to
* @param rank
* The initial rank
* @return The new iterator
*/
public ITmfContext createIterator(CtfLocationInfo ctfLocationData, long rank) {
try {
return new CtfIterator(fTrace, this, ctfLocationData, rank);
} catch (CTFException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
return null;
}
/**
* Create the 'CtfIterator' object from a CtfTmfContext.
*
* @param context
* The iterator will initially be pointing to this context
* @return A new CtfIterator object
* @since 1.0
*/
public ITmfContext createIteratorFromContext(CtfTmfContext context) {
return fIteratorManager.getIterator(context);
}
/**
* Dispose an iterator that was create with {@link #createIteratorFromContext}
*
* @param context
* The last context that was pointed to by the iterator (this is the
* 'key' to find the correct iterator to dispose).
* @since 1.0
*/
public void disposeContext(CtfTmfContext context) {
fIteratorManager.removeIterator(context);
}
// ------------------------------------------------------------------------
// Timestamp transformation functions
// ------------------------------------------------------------------------
/**
* @since 1.0
*/
@Override
public @NonNull ITmfTimestamp createTimestamp(long ts) {
return TmfTimestamp.fromNanos(getTimestampTransform().transform(ts));
}
private static int fCheckpointSize = -1;
@Override
public synchronized int getCheckpointSize() {
if (fCheckpointSize == -1) {
TmfCheckpoint c = new TmfCheckpoint(TmfTimestamp.fromNanos(0), new CtfLocation(0, 0), 0);
ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
b.clear();
c.serialize(b);
fCheckpointSize = b.position();
}
return fCheckpointSize;
}
@Override
protected ITmfTraceIndexer createIndexer(int interval) {
return new TmfBTreeTraceIndexer(this, interval);
}
@Override
public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
return new CtfLocation(bufferIn);
}
@Override
public boolean isComplete() {
if (getResource() == null) {
return true;
}
String host = null;
String port = null;
String sessionName = null;
try {
host = getResource().getPersistentProperty(CtfConstants.LIVE_HOST);
port = getResource().getPersistentProperty(CtfConstants.LIVE_PORT);
sessionName = getResource().getPersistentProperty(CtfConstants.LIVE_SESSION_NAME);
} catch (CoreException e) {
Activator.getDefault().logError(e.getMessage(), e);
// Something happened to the resource, assume we won't get any more
// data from it
return true;
}
return host == null || port == null || sessionName == null;
}
@Override
public void setComplete(final boolean isComplete) {
super.setComplete(isComplete);
try {
if (isComplete) {
getResource().setPersistentProperty(CtfConstants.LIVE_HOST, null);
getResource().setPersistentProperty(CtfConstants.LIVE_PORT, null);
getResource().setPersistentProperty(CtfConstants.LIVE_SESSION_NAME, null);
}
} catch (CoreException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
}
/**
* @return the number of estimated chunks of events read. This reads the file
* size of the trace and divides it by a factor and the average event
* size, this is not accurate but can give a ball park figure of how
* much is done.
* @since 2.1
*/
@Override
public int size() {
long size = 0;
CTFTrace trace = fTrace;
if (trace != null) {
Iterable<ICTFStream> streams = trace.getStreams();
for (ICTFStream stream : streams) {
for (CTFStreamInput si : stream.getStreamInputs()) {
size += si.getFile().length();
}
}
}
return (int) (size / REDUCTION_FACTOR / CTF_AVG_EVENT_SIZE);
}
/**
* @return the number of events divided a reduction factor. Is monotonic.
* @since 2.1
*/
@Override
public int progress() {
return (int) (getNbEvents() / REDUCTION_FACTOR);
}
/**
* @since 3.0
*/
@Override
public long cyclesToNanos(long cycles) {
// CTFTrace adds the clock offset in cycles to the input
CTFTrace trace = fTrace;
if (trace != null) {
return fTrace.timestampCyclesToNanos(cycles - trace.getOffset());
}
return 0;
}
/**
* @since 3.0
*/
@Override
public long nanosToCycles(long nanos) {
// CTFTrace subtracts the clock offset in cycles from the output
CTFTrace trace = fTrace;
if (trace != null) {
return trace.timestampNanoToCycles(nanos) + fTrace.getOffset();
}
return 0;
}
/**
* @since 3.0
*/
@Override
public ITmfTimestamp readStart() {
return getStartTime();
}
/**
* @since 3.0
*/
@Override
public ITmfTimestamp readEnd() {
try (CTFTraceReader reader = new CTFTraceReader(fTrace)) {
reader.goToLastEvent();
long end = reader.getEndTime();
return createTimestamp(end);
} catch (CTFException e) {
return null;
}
}
@Override
public Path trim(@NonNull TmfTimeRange range, @NonNull Path destinationPath, @NonNull IProgressMonitor monitor) throws CoreException {
CTFTrace trace = fTrace;
if (trace == null) {
return null;
}
try {
CTFTraceWriter ctfWriter = new CTFTraceWriter(trace);
String tracePath = destinationPath.toAbsolutePath().toString();
ctfWriter.copyPackets(range.getStartTime().toNanos(), range.getEndTime().toNanos(), tracePath);
return destinationPath;
} catch (CTFException e) {
Activator.getDefault().logError("Error writing trace : " + destinationPath, e); //$NON-NLS-1$
}
return null;
}
}