CTF: Do not recalculate the single clock each time in CTFTrace#getClock()
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / CTFTrace.java
index 4bbc41e1a51024076c4a4620236da1d195b04da9..4bb35847b7eb804f33a9a698b2460dc1b7ed7f38 100644 (file)
@@ -1,13 +1,15 @@
 /*******************************************************************************
- * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
+ * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
  *
  * All rights reserved. This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License v1.0 which
  * accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
- * Contributors: Matthew Khouzam - Initial API and implementation
- * Contributors: Alexandre Montplaisir - Initial API and implementation
+ * Contributors:
+ *     Matthew Khouzam - Initial API and implementation
+ *     Alexandre Montplaisir - Initial API and implementation
+ *     Simon Delisle - Replace LinkedList by TreeSet in callsitesByName attribute
  *******************************************************************************/
 
 package org.eclipse.linuxtools.ctf.core.trace;
@@ -22,30 +24,30 @@ import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileChannel.MapMode;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.UUID;
 
+import org.eclipse.linuxtools.ctf.core.event.CTFCallsite;
 import org.eclipse.linuxtools.ctf.core.event.CTFClock;
-import org.eclipse.linuxtools.ctf.core.event.EventDeclaration;
-import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
-import org.eclipse.linuxtools.ctf.core.event.types.ArrayDefinition;
+import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
+import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
+import org.eclipse.linuxtools.ctf.core.event.scope.IDefinitionScope;
+import org.eclipse.linuxtools.ctf.core.event.scope.LexicalScope;
 import org.eclipse.linuxtools.ctf.core.event.types.Definition;
-import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
+import org.eclipse.linuxtools.ctf.core.event.types.IDefinition;
 import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
 import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
 import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
-import org.eclipse.linuxtools.internal.ctf.core.event.io.BitBuffer;
+import org.eclipse.linuxtools.internal.ctf.core.event.CTFCallsiteComparator;
 import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
-import org.eclipse.linuxtools.internal.ctf.core.trace.Stream;
-import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInput;
-import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex;
+import org.eclipse.linuxtools.internal.ctf.core.event.types.ArrayDefinition;
 
 /**
  * A CTF trace on the file system.
@@ -58,60 +60,49 @@ import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex;
  * @author Matthew Khouzam
  * @version $Revision: 1.0 $
  */
-public class CTFTrace implements IDefinitionScope {
+public class CTFTrace implements IDefinitionScope, AutoCloseable {
 
-    /*
-     * (non-Javadoc)
-     *
-     * @see java.lang.Object#toString()
-     */
-    @SuppressWarnings("nls")
     @Override
     public String toString() {
         /* Only for debugging, shouldn't be externalized */
-        return "CTFTrace [path=" + path + ", major=" + major + ", minor="
-                + minor + ", uuid=" + uuid + "]";
+        return "CTFTrace [path=" + fPath + ", major=" + fMajor + ", minor=" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                + fMinor + ", uuid=" + fUuid + "]"; //$NON-NLS-1$ //$NON-NLS-2$
     }
 
     /**
      * The trace directory on the filesystem.
      */
-    private final File path;
-
-    /**
-     * The metadata parsing object.
-     */
-    private final Metadata metadata;
+    private final File fPath;
 
     /**
      * Major CTF version number
      */
-    private Long major;
+    private Long fMajor;
 
     /**
      * Minor CTF version number
      */
-    private Long minor;
+    private Long fMinor;
 
     /**
      * Trace UUID
      */
-    private UUID uuid;
+    private UUID fUuid;
 
     /**
      * Trace byte order
      */
-    private ByteOrder byteOrder;
+    private ByteOrder fByteOrder;
 
     /**
      * Packet header structure declaration
      */
-    private StructDeclaration packetHeaderDecl = null;
+    private StructDeclaration fPacketHeaderDecl = null;
 
     /**
      * The clock of the trace
      */
-    private CTFClock singleClock;
+    private CTFClock fSingleClock = null;
 
     /**
      * Packet header structure definition
@@ -119,39 +110,34 @@ public class CTFTrace implements IDefinitionScope {
      * This is only used when opening the trace files, to read the first packet
      * header and see if they are valid trace files.
      */
-    private StructDefinition packetHeaderDef;
+    private StructDefinition fPacketHeaderDef;
 
     /**
      * Collection of streams contained in the trace.
      */
-    private final HashMap<Long, Stream> streams;
+    private final Map<Long, CTFStream> fStreams = new HashMap<>();
 
     /**
      * Collection of environment variables set by the tracer
      */
-    private final HashMap<String, String> environment;
+    private final Map<String, String> fEnvironment = new HashMap<>();
 
     /**
      * Collection of all the clocks in a system.
      */
-    private final HashMap<String, CTFClock> clocks;
-
-    /** FileChannels to the streams */
-    private final List<FileChannel> streamFileChannels;
+    private final Map<String, CTFClock> fClocks = new HashMap<>();
 
     /** Handlers for the metadata files */
-    private final static FileFilter metadataFileFilter = new MetadataFileFilter();
-    private final static Comparator<File> metadataComparator = new MetadataComparator(); // $codepro.audit.disable
-                                                                                         // fieldJavadoc
+    private static final FileFilter METADATA_FILE_FILTER = new MetadataFileFilter();
+    private static final Comparator<File> METADATA_COMPARATOR = new MetadataComparator();
 
-    /** map of all the event types */
-    private final HashMap<Long,HashMap<Long, EventDeclaration>> eventDecs;
-    /** map of all the event types */
-    private final HashMap<StreamInput,HashMap<Long, EventDefinition>> eventDefs;
-    /** map of all the indexes */
-    private final HashMap<StreamInput, StreamInputPacketIndex> indexes;
+    /** Callsite helpers */
+    private CTFCallsiteComparator fCtfCallsiteComparator = new CTFCallsiteComparator();
 
+    private Map<String, TreeSet<CTFCallsite>> fCallsitesByName = new HashMap<>();
 
+    /** Callsite helpers */
+    private TreeSet<CTFCallsite> fCallsitesByIP = new TreeSet<>();
 
     // ------------------------------------------------------------------------
     // Constructors
@@ -179,78 +165,64 @@ public class CTFTrace implements IDefinitionScope {
      *             If no CTF trace was found at the path
      */
     public CTFTrace(File path) throws CTFReaderException {
-        this.path = path;
-        this.metadata = new Metadata(this);
+        fPath = path;
+        final Metadata metadata = new Metadata(this);
 
         /* Set up the internal containers for this trace */
-        streams = new HashMap<Long, Stream>();
-        environment = new HashMap<String, String>();
-        clocks = new HashMap<String, CTFClock>();
-        streamFileChannels = new LinkedList<FileChannel>();
-        eventDecs = new HashMap<Long, HashMap<Long, EventDeclaration>>();
-        eventDefs = new HashMap<StreamInput, HashMap<Long, EventDefinition>>();
-
-        if (!this.path.isDirectory()) {
+        if (!fPath.exists()) {
+            throw new CTFReaderException("Trace (" + path.getPath() + ") doesn't exist. Deleted or moved?"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (!fPath.isDirectory()) {
             throw new CTFReaderException("Path must be a valid directory"); //$NON-NLS-1$
         }
 
         /* Open and parse the metadata file */
-        metadata.parse();
+        metadata.parseFile();
+
+        init(path);
+    }
+
+    /**
+     * Streamed constructor
+     *
+     * @since 3.0
+     */
+    public CTFTrace() {
+        fPath = null;
+    }
+
+    private void init(File path) throws CTFReaderException {
 
         /* Open all the trace files */
-        /* Create the definitions needed to read things from the files */
-        if (packetHeaderDecl != null) {
-            packetHeaderDef = packetHeaderDecl.createDefinition(this,
-                    "packet.header"); //$NON-NLS-1$
-        }
 
         /* List files not called metadata and not hidden. */
-        File[] files = path.listFiles(metadataFileFilter);
-        Arrays.sort(files, metadataComparator);
-        indexes = new HashMap<StreamInput, StreamInputPacketIndex>();
+        File[] files = path.listFiles(METADATA_FILE_FILTER);
+        Arrays.sort(files, METADATA_COMPARATOR);
+
         /* Try to open each file */
         for (File streamFile : files) {
             openStreamInput(streamFile);
         }
 
         /* Create their index */
-        for (Map.Entry<Long, Stream> stream : streams.entrySet()) {
-            Set<StreamInput> inputs = stream.getValue().getStreamInputs();
-            for (StreamInput s : inputs) {
-                /*
-                 * Copy the events
-                 */
-                Iterator<Entry<Long, EventDeclaration>> it = s.getStream()
-                        .getEvents().entrySet().iterator();
-                while (it.hasNext()) {
-                    Map.Entry<Long, EventDeclaration> pairs = it.next();
-                    Long eventNum = pairs.getKey();
-                    EventDeclaration eventDec = pairs.getValue();
-                    getEvents(s.getStream().getId()).put(eventNum, eventDec);
-                }
-
-                /*
-                 * index the trace
-                 */
-                s.setupIndex();
+        for (CTFStream stream : getStreams()) {
+            Set<CTFStreamInput> inputs = stream.getStreamInputs();
+            for (CTFStreamInput s : inputs) {
+                addStream(s);
             }
         }
     }
 
+    /**
+     * Dispose the trace
+     *
+     * FIXME Not needed anymore, class doesn't need to be AutoCloseable.
+     *
+     * @since 3.0
+     */
     @Override
-    protected void finalize() throws Throwable {
-        /* If this trace gets closed, release the descriptors to the streams */
-        for (FileChannel fc : streamFileChannels) {
-            if (fc != null) {
-                try {
-                    fc.close();
-                } catch (IOException e) {
-                    // do nothing it's ok, we tried to close it.
-                }
-            }
-        }
-        super.finalize();
-
+    public void close() {
     }
 
     // ------------------------------------------------------------------------
@@ -263,33 +235,10 @@ public class CTFTrace implements IDefinitionScope {
      * @param streamId
      *            The ID of the stream from which to read
      * @return The Hash map with the event declarations
+     * @since 2.0
      */
-    public HashMap<Long, EventDeclaration> getEvents(Long streamId) {
-        return eventDecs.get(streamId);
-    }
-
-    /**
-     * Gets an index for a given StreamInput
-     * @param id the StreamInput
-     * @return The index
-     */
-    public StreamInputPacketIndex getIndex(StreamInput id){
-        if(! indexes.containsKey(id)){
-            indexes.put(id, new StreamInputPacketIndex());
-        }
-        return indexes.get(id);
-    }
-
-    /**
-     * Gets an event Declaration hashmap for a given StreamInput
-     * @param id the StreamInput
-     * @return the hashmap with the event definitions
-     */
-    public HashMap<Long, EventDefinition> getEventDefs(StreamInput id) {
-        if(! eventDefs.containsKey(id)){
-            eventDefs.put(id, new HashMap<Long, EventDefinition>());
-        }
-        return eventDefs.get(id);
+    public Map<Long, IEventDeclaration> getEvents(Long streamId) {
+        return fStreams.get(streamId).getEvents();
     }
 
     /**
@@ -300,8 +249,9 @@ public class CTFTrace implements IDefinitionScope {
      * @param id
      *            the ID of the event
      * @return the event declaration
+     * @since 2.0
      */
-    public EventDeclaration getEventType(long streamId, long id) {
+    public IEventDeclaration getEventType(long streamId, long id) {
         return getEvents(streamId).get(id);
     }
 
@@ -311,9 +261,10 @@ public class CTFTrace implements IDefinitionScope {
      * @param id
      *            Long the id of the stream
      * @return Stream the stream that we need
+     * @since 3.0
      */
-    public Stream getStream(Long id) {
-        return streams.get(id);
+    public CTFStream getStream(Long id) {
+        return fStreams.get(id);
     }
 
     /**
@@ -322,7 +273,7 @@ public class CTFTrace implements IDefinitionScope {
      * @return int the number of streams
      */
     public int nbStreams() {
-        return streams.size();
+        return fStreams.size();
     }
 
     /**
@@ -332,7 +283,7 @@ public class CTFTrace implements IDefinitionScope {
      *            long the major version
      */
     public void setMajor(long major) {
-        this.major = major;
+        fMajor = major;
     }
 
     /**
@@ -342,7 +293,7 @@ public class CTFTrace implements IDefinitionScope {
      *            long the minor version
      */
     public void setMinor(long minor) {
-        this.minor = minor;
+        fMinor = minor;
     }
 
     /**
@@ -352,7 +303,7 @@ public class CTFTrace implements IDefinitionScope {
      *            UUID
      */
     public void setUUID(UUID uuid) {
-        this.uuid = uuid;
+        fUuid = uuid;
     }
 
     /**
@@ -362,7 +313,7 @@ public class CTFTrace implements IDefinitionScope {
      *            ByteOrder of the trace, can be little-endian or big-endian
      */
     public void setByteOrder(ByteOrder byteOrder) {
-        this.byteOrder = byteOrder;
+        fByteOrder = byteOrder;
     }
 
     /**
@@ -372,16 +323,17 @@ public class CTFTrace implements IDefinitionScope {
      *            StructDeclaration the header in structdeclaration form
      */
     public void setPacketHeader(StructDeclaration packetHeader) {
-        this.packetHeaderDecl = packetHeader;
+        fPacketHeaderDecl = packetHeader;
     }
 
     /**
-     * Method majortIsSet is the major version number set?
+     * Method majorIsSet is the major version number set?
      *
      * @return boolean is the major set?
+     * @since 3.0
      */
-    public boolean majortIsSet() {
-        return major != null;
+    public boolean majorIsSet() {
+        return fMajor != null;
     }
 
     /**
@@ -390,16 +342,17 @@ public class CTFTrace implements IDefinitionScope {
      * @return boolean is the minor set?
      */
     public boolean minorIsSet() {
-        return minor != null;
+        return fMinor != null;
     }
 
     /**
      * Method UUIDIsSet is the UUID set?
      *
      * @return boolean is the UUID set?
+     * @since 2.0
      */
-    public boolean UUIDIsSet() {
-        return uuid != null;
+    public boolean uuidIsSet() {
+        return fUuid != null;
     }
 
     /**
@@ -408,7 +361,7 @@ public class CTFTrace implements IDefinitionScope {
      * @return boolean is the byteorder set?
      */
     public boolean byteOrderIsSet() {
-        return byteOrder != null;
+        return fByteOrder != null;
     }
 
     /**
@@ -417,7 +370,7 @@ public class CTFTrace implements IDefinitionScope {
      * @return boolean is the packet header set?
      */
     public boolean packetHeaderIsSet() {
-        return packetHeaderDecl != null;
+        return fPacketHeaderDecl != null;
     }
 
     /**
@@ -426,7 +379,7 @@ public class CTFTrace implements IDefinitionScope {
      * @return UUID gets the trace UUID
      */
     public UUID getUUID() {
-        return uuid;
+        return fUuid;
     }
 
     /**
@@ -435,7 +388,7 @@ public class CTFTrace implements IDefinitionScope {
      * @return long gets the trace major version
      */
     public long getMajor() {
-        return major;
+        return fMajor;
     }
 
     /**
@@ -444,7 +397,7 @@ public class CTFTrace implements IDefinitionScope {
      * @return long gets the trace minor version
      */
     public long getMinor() {
-        return minor;
+        return fMinor;
     }
 
     /**
@@ -452,8 +405,8 @@ public class CTFTrace implements IDefinitionScope {
      *
      * @return ByteOrder gets the trace byte order
      */
-    public ByteOrder getByteOrder() {
-        return byteOrder;
+    public final ByteOrder getByteOrder() {
+        return fByteOrder;
     }
 
     /**
@@ -462,7 +415,7 @@ public class CTFTrace implements IDefinitionScope {
      * @return StructDeclaration gets the trace packet header
      */
     public StructDeclaration getPacketHeader() {
-        return packetHeaderDecl;
+        return fPacketHeaderDecl;
     }
 
     /**
@@ -471,16 +424,17 @@ public class CTFTrace implements IDefinitionScope {
      * @return File the path in "File" format.
      */
     public File getTraceDirectory() {
-        return path;
+        return fPath;
     }
 
     /**
-     * Method getStreams get all the streams in a map format.
+     * Get all the streams as an iterable.
      *
-     * @return Map<Long,Stream> a map of all the streams.
+     * @return Iterable&lt;Stream&gt; an iterable over streams.
+     * @since 3.0
      */
-    public Map<Long, Stream> getStreams() {
-        return streams;
+    public Iterable<CTFStream> getStreams() {
+        return fStreams.values();
     }
 
     /**
@@ -489,18 +443,38 @@ public class CTFTrace implements IDefinitionScope {
      * @return String the path of the trace directory, in string format.
      * @see java.io.File#getPath()
      */
-    @Override
     public String getPath() {
-        return path.getPath();
+        return (fPath != null) ? fPath.getPath() : ""; //$NON-NLS-1$
     }
 
+
     // ------------------------------------------------------------------------
     // Operations
     // ------------------------------------------------------------------------
 
+    private void addStream(CTFStreamInput s) {
+
+        /*
+         * Copy the events
+         */
+        Iterator<Entry<Long, IEventDeclaration>> it = s.getStream()
+                .getEvents().entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<Long, IEventDeclaration> pairs = it.next();
+            Long eventNum = pairs.getKey();
+            IEventDeclaration eventDec = pairs.getValue();
+            getEvents(s.getStream().getId()).put(eventNum, eventDec);
+        }
+
+        /*
+         * index the trace
+         */
+        s.setupIndex();
+    }
+
     /**
      * Tries to open the given file, reads the first packet header of the file
-     * and check its validity.
+     * and check its validity. This will add a file to a stream as a streaminput
      *
      * @param streamFile
      *            A trace file in the trace directory.
@@ -508,85 +482,95 @@ public class CTFTrace implements IDefinitionScope {
      *            Which index in the class' streamFileChannel array this file
      *            must use
      * @throws CTFReaderException
+     *             if there is a file error
      */
-    private void openStreamInput(File streamFile) throws CTFReaderException {
+    private CTFStream openStreamInput(File streamFile) throws CTFReaderException {
         MappedByteBuffer byteBuffer;
         BitBuffer streamBitBuffer;
-        Stream stream;
-        FileChannel fc;
+        CTFStream stream;
 
         if (!streamFile.canRead()) {
             throw new CTFReaderException("Unreadable file : " //$NON-NLS-1$
                     + streamFile.getPath());
         }
 
-        try {
-            /* Open the file and get the FileChannel */
-            fc = new FileInputStream(streamFile).getChannel();
-            streamFileChannels.add(fc);
-
+        try (FileInputStream fis = new FileInputStream(streamFile);
+                FileChannel fc = fis.getChannel()) {
             /* Map one memory page of 4 kiB */
-            byteBuffer = fc.map(MapMode.READ_ONLY, 0, 4096);
+            byteBuffer = fc.map(MapMode.READ_ONLY, 0, (int) Math.min(fc.size(), 4096L));
+            if( byteBuffer == null){
+                throw new IllegalStateException("Failed to allocate memory"); //$NON-NLS-1$
+            }
         } catch (IOException e) {
             /* Shouldn't happen at this stage if every other check passed */
-            throw new CTFReaderException();
+            throw new CTFReaderException(e);
         }
 
         /* Create a BitBuffer with this mapping and the trace byte order */
         streamBitBuffer = new BitBuffer(byteBuffer, this.getByteOrder());
 
-        if (packetHeaderDef != null) {
+        if (fPacketHeaderDecl != null) {
             /* Read the packet header */
-            packetHeaderDef.read(streamBitBuffer);
+            fPacketHeaderDef = fPacketHeaderDecl.createDefinition(this, LexicalScope.PACKET_HEADER, streamBitBuffer);
 
             /* Check the magic number */
-            IntegerDefinition magicDef = (IntegerDefinition) packetHeaderDef
-                    .lookupDefinition("magic"); //$NON-NLS-1$
+            IntegerDefinition magicDef = (IntegerDefinition) fPacketHeaderDef.lookupDefinition("magic"); //$NON-NLS-1$
             int magic = (int) magicDef.getValue();
             if (magic != Utils.CTF_MAGIC) {
                 throw new CTFReaderException("CTF magic mismatch"); //$NON-NLS-1$
             }
 
             /* Check UUID */
-            ArrayDefinition uuidDef = (ArrayDefinition) packetHeaderDef
-                    .lookupDefinition("uuid"); //$NON-NLS-1$
+            IDefinition lookupDefinition = fPacketHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
+            ArrayDefinition uuidDef = (ArrayDefinition) lookupDefinition;
             if (uuidDef != null) {
-                byte[] uuidArray = new byte[Utils.UUID_LEN];
+                UUID otheruuid = Utils.getUUIDfromDefinition(uuidDef);
 
-                for (int i = 0; i < Utils.UUID_LEN; i++) {
-                    IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef
-                            .getElem(i);
-                    uuidArray[i] = (byte) uuidByteDef.getValue();
-                }
-
-                UUID otheruuid = Utils.makeUUID(uuidArray);
-
-                if (!this.uuid.equals(otheruuid)) {
+                if (!fUuid.equals(otheruuid)) {
                     throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
                 }
             }
 
             /* Read the stream ID */
-            Definition streamIDDef = packetHeaderDef.lookupDefinition("stream_id"); //$NON-NLS-1$
+            IDefinition streamIDDef = fPacketHeaderDef.lookupDefinition("stream_id"); //$NON-NLS-1$
 
-            if (streamIDDef instanceof IntegerDefinition) { //this doubles as a null check
+            if (streamIDDef instanceof IntegerDefinition) { // this doubles as a
+                                                            // null check
                 long streamID = ((IntegerDefinition) streamIDDef).getValue();
-                stream = streams.get(streamID);
+                stream = fStreams.get(streamID);
             } else {
                 /* No stream_id in the packet header */
-                stream = streams.get(null);
+                stream = fStreams.get(null);
             }
 
         } else {
             /* No packet header, we suppose there is only one stream */
-            stream = streams.get(null);
+            stream = fStreams.get(null);
         }
 
-        /* Create the stream input */
-        StreamInput streamInput = new StreamInput(stream, fc, streamFile);
+        if (stream == null) {
+            throw new CTFReaderException("Unexpected end of stream"); //$NON-NLS-1$
+        }
 
-        /* Add a reference to the streamInput in the stream */
-        stream.addInput(streamInput);
+        /*
+         * Create the stream input and add a reference to the streamInput in the
+         * stream
+         */
+        stream.addInput(new CTFStreamInput(stream, streamFile));
+
+        return stream;
+    }
+
+    // ------------------------------------------------------------------------
+    // IDefinitionScope
+    // ------------------------------------------------------------------------
+
+    /**
+     * @since 3.0
+     */
+    @Override
+    public LexicalScope getScopePath() {
+        return LexicalScope.TRACE;
     }
 
     /**
@@ -595,31 +579,49 @@ public class CTFTrace implements IDefinitionScope {
      * @param lookupPath
      *            String
      * @return Definition
-     * @see org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope#lookupDefinition(String)
+     * @see org.eclipse.linuxtools.ctf.core.event.scope.IDefinitionScope#lookupDefinition(String)
      */
     @Override
     public Definition lookupDefinition(String lookupPath) {
-        if (lookupPath.equals("trace.packet.header")) { //$NON-NLS-1$
-            return packetHeaderDef;
+        if (lookupPath.equals(LexicalScope.TRACE_PACKET_HEADER.toString())) {
+            return fPacketHeaderDef;
         }
         return null;
     }
 
+    // ------------------------------------------------------------------------
+    // Live trace reading
+    // ------------------------------------------------------------------------
+
     /**
-     * Adds a new stream to the trace.
+     * Add a new stream file to support new streams while the trace is being
+     * read.
+     *
+     * @param streamFile
+     *            the file of the stream
+     * @throws CTFReaderException
+     *             A stream had an issue being read
+     * @since 3.0
+     */
+    public void addStreamFile(File streamFile) throws CTFReaderException {
+        openStreamInput(streamFile);
+    }
+
+    /**
+     * Registers a new stream to the trace.
      *
      * @param stream
      *            A stream object.
      * @throws ParseException
      *             If there was some problem reading the metadata
+     * @since 3.0
      */
-    public void addStream(Stream stream) throws ParseException {
-
+    public void addStream(CTFStream stream) throws ParseException {
         /*
          * If there is already a stream without id (the null key), it must be
          * the only one
          */
-        if (streams.get(null) != null) {
+        if (fStreams.get(null) != null) {
             throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
         }
 
@@ -627,67 +629,68 @@ public class CTFTrace implements IDefinitionScope {
          * If the stream we try to add has the null key, it must be the only
          * one. Thus, if the streams container is not empty, it is not valid.
          */
-        if ((stream.getId() == null) && (streams.size() != 0)) {
+        if ((stream.getId() == null) && (fStreams.size() != 0)) {
             throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
         }
 
-        /* If a stream with the same ID already exists, it is not valid. */
-        if (streams.get(stream.getId()) != null) {
+        /*
+         * If a stream with the same ID already exists, it is not valid.
+         */
+        CTFStream existingStream = fStreams.get(stream.getId());
+        if (existingStream != null) {
             throw new ParseException("Stream id already exists"); //$NON-NLS-1$
         }
 
-        /* It should be ok now. */
-        streams.put(stream.getId(), stream);
-        eventDecs.put(stream.getId(), new HashMap<Long,EventDeclaration>());
-    }
-
-    /**
-     * gets the Environment variables from the trace metadata (See CTF spec)
-     * @return the environment variables in a hashmap form (key value)
-     */
-    public HashMap<String, String> getEnvironment() {
-        return environment;
+        /* This stream is valid and has a unique id. */
+        fStreams.put(stream.getId(), stream);
     }
 
     /**
-     * Look up a specific environment variable
-     * @param key the key to look for
-     * @return the value of the variable, can be null.
+     * Gets the Environment variables from the trace metadata (See CTF spec)
+     *
+     * @return The environment variables in the form of an unmodifiable map
+     *         (key, value)
+     * @since 2.0
      */
-    public String lookupEnvironment(String key) {
-        return environment.get(key);
+    public Map<String, String> getEnvironment() {
+        return Collections.unmodifiableMap(fEnvironment);
     }
 
     /**
      * Add a variable to the environment variables
-     * @param varName the name of the variable
-     * @param varValue the value of the variable
+     *
+     * @param varName
+     *            the name of the variable
+     * @param varValue
+     *            the value of the variable
      */
     public void addEnvironmentVar(String varName, String varValue) {
-        environment.put(varName, varValue);
+        fEnvironment.put(varName, varValue);
     }
 
     /**
      * Add a clock to the clock list
-     * @param nameValue the name of the clock (full name with scope)
-     * @param ctfClock the clock
+     *
+     * @param nameValue
+     *            the name of the clock (full name with scope)
+     * @param ctfClock
+     *            the clock
      */
     public void addClock(String nameValue, CTFClock ctfClock) {
-        clocks.put(nameValue, ctfClock);
+        fClocks.put(nameValue, ctfClock);
     }
 
     /**
      * gets the clock with a specific name
-     * @param name the name of the clock.
+     *
+     * @param name
+     *            the name of the clock.
      * @return the clock
      */
     public CTFClock getClock(String name) {
-        return clocks.get(name);
+        return fClocks.get(name);
     }
 
-
-
-
     /**
      * gets the clock if there is only one. (this is 100% of the use cases as of
      * June 2012)
@@ -695,9 +698,12 @@ public class CTFTrace implements IDefinitionScope {
      * @return the clock
      */
     public final CTFClock getClock() {
-        if (clocks.size() == 1) {
-            singleClock = clocks.get(clocks.keySet().iterator().next());
-            return singleClock;
+        if (fSingleClock != null && fClocks.size() == 1) {
+            return fSingleClock;
+        }
+        if (fClocks.size() == 1) {
+            fSingleClock = fClocks.get(fClocks.keySet().iterator().next());
+            return fSingleClock;
         }
         return null;
     }
@@ -711,7 +717,7 @@ public class CTFTrace implements IDefinitionScope {
         if (getClock() == null) {
             return 0;
         }
-        return singleClock.getClockOffset();
+        return fSingleClock.getClockOffset();
     }
 
     /**
@@ -719,11 +725,41 @@ public class CTFTrace implements IDefinitionScope {
      *
      * @return the time offset of a clock with respect to UTC in nanoseconds
      */
-    private final double getTimeScale() {
+    private double getTimeScale() {
         if (getClock() == null) {
             return 1.0;
         }
-        return singleClock.getClockScale();
+        return fSingleClock.getClockScale();
+    }
+
+    /**
+     * Gets the current first packet start time
+     * @return the current start time
+     * @since 3.0
+     */
+    public long getCurrentStartTime() {
+        long currentStart = Long.MAX_VALUE;
+        for (CTFStream stream : fStreams.values()) {
+            for (CTFStreamInput si : stream.getStreamInputs()) {
+                currentStart = Math.min(currentStart, si.getIndex().getEntries().get(0).getTimestampBegin());
+            }
+        }
+        return timestampCyclesToNanos(currentStart);
+    }
+
+    /**
+     * Gets the current last packet end time
+     * @return the current end time
+     * @since 3.0
+     */
+    public long getCurrentEndTime() {
+        long currentEnd = Long.MIN_VALUE;
+        for (CTFStream stream : fStreams.values()) {
+            for (CTFStreamInput si : stream.getStreamInputs()) {
+                currentEnd = Math.max(currentEnd, si.getTimestampEnd());
+            }
+        }
+        return timestampCyclesToNanos(currentEnd);
     }
 
     /**
@@ -731,11 +767,11 @@ public class CTFTrace implements IDefinitionScope {
      *
      * @return if the trace is in ns or cycles.
      */
-    private final boolean clockNeedsScale() {
+    private boolean clockNeedsScale() {
         if (getClock() == null) {
             return false;
         }
-        return singleClock.isClockScaled();
+        return fSingleClock.isClockScaled();
     }
 
     /**
@@ -743,17 +779,18 @@ public class CTFTrace implements IDefinitionScope {
      *
      * @return 1.0 / scale
      */
-    private final double getInverseTimeScale() {
+    private double getInverseTimeScale() {
         if (getClock() == null) {
             return 1.0;
         }
-        return singleClock.getClockAntiScale();
+        return fSingleClock.getClockAntiScale();
     }
 
     /**
      * @param cycles
      *            clock cycles since boot
      * @return time in nanoseconds UTC offset
+     * @since 2.0
      */
     public long timestampCyclesToNanos(long cycles) {
         long retVal = cycles + getOffset();
@@ -771,6 +808,7 @@ public class CTFTrace implements IDefinitionScope {
      * @param nanos
      *            time in nanoseconds UTC offset
      * @return clock cycles since boot.
+     * @since 2.0
      */
     public long timestampNanoToCycles(long nanos) {
         long retVal;
@@ -787,28 +825,123 @@ public class CTFTrace implements IDefinitionScope {
     }
 
     /**
-     * Does a given stream contain any events?
-     * @param id the stream ID
-     * @return true if the stream has events.
+     * Adds a callsite
+     *
+     * @param eventName
+     *            the event name of the callsite
+     * @param funcName
+     *            the name of the callsite function
+     * @param ip
+     *            the ip of the callsite
+     * @param fileName
+     *            the filename of the callsite
+     * @param lineNumber
+     *            the line number of the callsite
+     */
+    public void addCallsite(String eventName, String funcName, long ip,
+            String fileName, long lineNumber) {
+        final CTFCallsite cs = new CTFCallsite(eventName, funcName, ip,
+                fileName, lineNumber);
+        TreeSet<CTFCallsite> csl = fCallsitesByName.get(eventName);
+        if (csl == null) {
+            csl = new TreeSet<>(fCtfCallsiteComparator);
+            fCallsitesByName.put(eventName, csl);
+        }
+
+        csl.add(cs);
+
+        fCallsitesByIP.add(cs);
+    }
+
+    /**
+     * Gets the set of callsites associated to an event name. O(1)
+     *
+     * @param eventName
+     *            the event name
+     * @return the callsite set can be empty
+     * @since 3.0
      */
-    public boolean hasEvents(Long id){
-        return eventDecs.containsKey(id);
+    public TreeSet<CTFCallsite> getCallsiteCandidates(String eventName) {
+        TreeSet<CTFCallsite> retVal = fCallsitesByName.get(eventName);
+        if (retVal == null) {
+            retVal = new TreeSet<>(fCtfCallsiteComparator);
+        }
+        return retVal;
     }
 
     /**
-     * Add an event declaration map to the events map.
-     * @param id the id of a stream
-     * @return the hashmap containing events.
+     * The I'm feeling lucky of getCallsiteCandidates O(1)
+     *
+     * @param eventName
+     *            the event name
+     * @return the first callsite that has that event name, can be null
+     * @since 1.2
      */
-    public HashMap<Long, EventDeclaration> createEvents(Long id){
-        HashMap<Long, EventDeclaration> value = eventDecs.get(id);
-        if( value == null ) {
-            value = new HashMap<Long, EventDeclaration>();
-            eventDecs.put(id, value);
+    public CTFCallsite getCallsite(String eventName) {
+        TreeSet<CTFCallsite> callsites = fCallsitesByName.get(eventName);
+        if (callsites != null) {
+            return callsites.first();
         }
-        return value;
+        return null;
+    }
+
+    /**
+     * Gets a callsite from the instruction pointer O(log(n))
+     *
+     * @param ip
+     *            the instruction pointer to lookup
+     * @return the callsite just before that IP in the list remember the IP is
+     *         backwards on X86, can be null if no callsite is before the IP.
+     * @since 1.2
+     */
+    public CTFCallsite getCallsite(long ip) {
+        CTFCallsite cs = new CTFCallsite(null, null, ip, null, 0L);
+        return fCallsitesByIP.ceiling(cs);
     }
 
+    /**
+     * Gets a callsite using the event name and instruction pointer O(log(n))
+     *
+     * @param eventName
+     *            the name of the event
+     * @param ip
+     *            the instruction pointer
+     * @return the closest matching callsite, can be null
+     */
+    public CTFCallsite getCallsite(String eventName, long ip) {
+        final TreeSet<CTFCallsite> candidates = fCallsitesByName.get(eventName);
+        if (candidates == null) {
+            return null;
+        }
+        final CTFCallsite dummyCs = new CTFCallsite(null, null, ip, null, -1);
+        final CTFCallsite callsite = candidates.ceiling(dummyCs);
+        if (callsite == null) {
+            return candidates.floor(dummyCs);
+        }
+        return callsite;
+    }
+
+    /**
+     * Add a new stream
+     *
+     * @param id
+     *            the ID of the stream
+     * @param streamFile
+     *            new file in the stream
+     * @throws CTFReaderException
+     *             The file must exist
+     * @since 3.0
+     */
+    public void addStream(long id, File streamFile) throws CTFReaderException {
+        CTFStream stream = null;
+        if (fStreams.containsKey(id)) {
+            stream = fStreams.get(id);
+        } else {
+            stream = new CTFStream(this);
+            fStreams.put(id, stream);
+        }
+        stream.addInput(new CTFStreamInput(stream, streamFile));
+    }
 }
 
 class MetadataFileFilter implements FileFilter {
This page took 0.039482 seconds and 5 git commands to generate.