X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=org.eclipse.linuxtools.ctf.core%2Fsrc%2Forg%2Feclipse%2Flinuxtools%2Fctf%2Fcore%2Ftrace%2FCTFTrace.java;h=7bb19730fe8c4cce8279e57f40084e4d402a2337;hb=ab04fc6bc48d6ebda9c00071b8e4f3077421e01e;hp=fefbc593c45fca89cbfe0219f78e73d1ce61832a;hpb=7179cae2ac2c6dfc0fab1379e050ed329ae9758c;p=deliverable%2Ftracecompass.git diff --git a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java index fefbc593c4..7bb19730fe 100644 --- a/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java +++ b/org.eclipse.linuxtools.ctf.core/src/org/eclipse/linuxtools/ctf/core/trace/CTFTrace.java @@ -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; @@ -16,31 +18,41 @@ import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; +import java.io.Serializable; import java.nio.ByteOrder; 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.EventDefinition; +import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration; import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer; -import org.eclipse.linuxtools.ctf.core.event.metadata.exceptions.ParseException; import org.eclipse.linuxtools.ctf.core.event.types.ArrayDefinition; 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.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.Activator; +import org.eclipse.linuxtools.internal.ctf.core.event.CTFCallsiteComparator; +import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException; /** - * CTFTrace - *

+ * A CTF trace on the file system. + * * Represents a trace on the filesystem. It is responsible of parsing the * metadata, creating declarations data structures, indexing the event packets * (in other words, all the work that can be shared between readers), but the @@ -49,59 +61,50 @@ import org.eclipse.linuxtools.internal.ctf.core.Activator; * @author Matthew Khouzam * @version $Revision: 1.0 $ */ -public class CTFTrace implements IDefinitionScope { - - // ------------------------------------------------------------------------ - // Attributes - // ------------------------------------------------------------------------ +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=" + + fMinor + ", uuid=" + fUuid + "]"; } /** * 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; + private StructDeclaration fPacketHeaderDecl = null; + + /** + * The clock of the trace + */ + private CTFClock fSingleClock; /** * Packet header structure definition @@ -109,23 +112,37 @@ 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 streams = new HashMap(); + private final Map fStreams = new HashMap<>(); /** * Collection of environment variables set by the tracer */ - private final HashMap environment = new HashMap(); + private final Map fEnvironment = new HashMap<>(); /** * Collection of all the clocks in a system. */ - private final HashMap clocks = new HashMap(); + private final Map fClocks = new HashMap<>(); + + /** FileInputStreams to the streams */ + private final List fFileInputStreams = new LinkedList<>(); + + /** Handlers for the metadata files */ + private static final FileFilter METADATA_FILE_FILTER = new MetadataFileFilter(); + private static final Comparator METADATA_COMPARATOR = new MetadataComparator(); + + /** Callsite helpers */ + private CTFCallsiteComparator fCtfCallsiteComparator = new CTFCallsiteComparator(); + + private Map> fCallsitesByName = new HashMap<>(); + /** Callsite helpers */ + private TreeSet fCallsitesByIP = new TreeSet<>(); // ------------------------------------------------------------------------ // Constructors @@ -135,11 +152,13 @@ public class CTFTrace implements IDefinitionScope { * Trace constructor. * * @param path - * Filesystem path of the trace directory. - * @throws IOException + * Filesystem path of the trace directory + * @throws CTFReaderException + * If no CTF trace was found at the path */ public CTFTrace(String path) throws CTFReaderException { this(new File(path)); + } /** @@ -148,33 +167,141 @@ public class CTFTrace implements IDefinitionScope { * @param path * Filesystem path of the trace directory. * @throws CTFReaderException + * If no CTF trace was found at the path */ - @SuppressWarnings("unqualified-field-access") public CTFTrace(File path) throws CTFReaderException { - this.path = path; + fPath = path; + final Metadata metadata = new Metadata(this); - metadata = new Metadata(this); + /* Set up the internal containers for this trace */ + if (!fPath.exists()) { + throw new CTFReaderException("Trace (" + path.getPath() + ") doesn't exist. Deleted or moved?"); //$NON-NLS-1$ //$NON-NLS-2$ + } - if (!this.path.isDirectory()) { + if (!fPath.isDirectory()) { throw new CTFReaderException("Path must be a valid directory"); //$NON-NLS-1$ } - this.open(); + /* Open and parse the metadata file */ + metadata.parseFile(); + + init(path); + } + + /** + * Streamed constructor + * + * @since 3.0 + */ + public CTFTrace() { + fPath = null; + init(); + } + + private void init() { + /* Create the definitions needed to read things from the files */ + if (fPacketHeaderDecl != null) { + fPacketHeaderDef = fPacketHeaderDecl.createDefinition(this, "packet.header"); //$NON-NLS-1$ + } + } + + private void init(File path) throws CTFReaderException { + + init(); + + /* Open all the trace files */ + + /* List files not called metadata and not hidden. */ + 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 (Stream stream : getStreams()) { + Set inputs = stream.getStreamInputs(); + for (StreamInput s : inputs) { + addStream(s); + } + } + } + + /** + * Dispose the trace + * + * @since 3.0 + */ + @Override + public void close() { + for (FileInputStream fis : fFileInputStreams) { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + // do nothing it's ok, we tried to close it. + } + } + } } // ------------------------------------------------------------------------ // Getters/Setters/Predicates // ------------------------------------------------------------------------ + /** + * Gets an event declaration hash map for a given streamID + * + * @param streamId + * The ID of the stream from which to read + * @return The Hash map with the event declarations + * @since 2.0 + */ + public Map getEvents(Long streamId) { + return fStreams.get(streamId).getEvents(); + } + + /** + * Gets an event Declaration hashmap for a given StreamInput + * + * @param id + * the StreamInput + * @return an empty hashmap, please see deprecated + * @since 2.0 + * @deprecated You should be using + * {@link StreamInputReader#getEventDefinitions()} instead. + */ + @Deprecated + public Map getEventDefs(StreamInput id) { + return new HashMap<>(); + } + + /** + * Get an event by it's ID + * + * @param streamId + * The ID of the stream from which to read + * @param id + * the ID of the event + * @return the event declaration + * @since 2.0 + */ + public IEventDeclaration getEventType(long streamId, long id) { + return getEvents(streamId).get(id); + } + /** * Method getStream gets the stream for a given id * * @param id * Long the id of the stream * @return Stream the stream that we need + * @since 2.0 */ public Stream getStream(Long id) { - return streams.get(id); + return fStreams.get(id); } /** @@ -183,7 +310,7 @@ public class CTFTrace implements IDefinitionScope { * @return int the number of streams */ public int nbStreams() { - return streams.size(); + return fStreams.size(); } /** @@ -193,7 +320,7 @@ public class CTFTrace implements IDefinitionScope { * long the major version */ public void setMajor(long major) { - this.major = major; + fMajor = major; } /** @@ -203,7 +330,7 @@ public class CTFTrace implements IDefinitionScope { * long the minor version */ public void setMinor(long minor) { - this.minor = minor; + fMinor = minor; } /** @@ -213,7 +340,7 @@ public class CTFTrace implements IDefinitionScope { * UUID */ public void setUUID(UUID uuid) { - this.uuid = uuid; + fUuid = uuid; } /** @@ -223,7 +350,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; } /** @@ -233,16 +360,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; } /** @@ -251,16 +379,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; } /** @@ -269,7 +398,7 @@ public class CTFTrace implements IDefinitionScope { * @return boolean is the byteorder set? */ public boolean byteOrderIsSet() { - return byteOrder != null; + return fByteOrder != null; } /** @@ -278,7 +407,7 @@ public class CTFTrace implements IDefinitionScope { * @return boolean is the packet header set? */ public boolean packetHeaderIsSet() { - return packetHeaderDecl != null; + return fPacketHeaderDecl != null; } /** @@ -287,7 +416,7 @@ public class CTFTrace implements IDefinitionScope { * @return UUID gets the trace UUID */ public UUID getUUID() { - return uuid; + return fUuid; } /** @@ -296,7 +425,7 @@ public class CTFTrace implements IDefinitionScope { * @return long gets the trace major version */ public long getMajor() { - return major; + return fMajor; } /** @@ -305,7 +434,7 @@ public class CTFTrace implements IDefinitionScope { * @return long gets the trace minor version */ public long getMinor() { - return minor; + return fMinor; } /** @@ -313,8 +442,8 @@ public class CTFTrace implements IDefinitionScope { * * @return ByteOrder gets the trace byte order */ - public ByteOrder getByteOrder() { - return byteOrder; + public final ByteOrder getByteOrder() { + return fByteOrder; } /** @@ -323,7 +452,7 @@ public class CTFTrace implements IDefinitionScope { * @return StructDeclaration gets the trace packet header */ public StructDeclaration getPacketHeader() { - return packetHeaderDecl; + return fPacketHeaderDecl; } /** @@ -332,16 +461,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 a map of all the streams. + * @return Iterable<Stream> an iterable over streams. + * @since 3.0 */ - public Map getStreams() { - return streams; + public Iterable getStreams() { + return fStreams.values(); } /** @@ -352,202 +482,135 @@ public class CTFTrace implements IDefinitionScope { */ @Override public String getPath() { - return path.getPath(); + return (fPath != null) ? fPath.getPath() : ""; //$NON-NLS-1$ } // ------------------------------------------------------------------------ // Operations // ------------------------------------------------------------------------ - /** - * Opens the trace and creates the index. - * - * @throws CTFReaderException - */ - private void open() throws CTFReaderException { - /* Open and parse the metadata file */ - openTraceMetadata(); + private void addStream(StreamInput s) { - if (Activator.getDefault() != null) { - Activator.getDefault().log(metadata.toString()); - } - /* Open all the trace files */ - openStreamInputs(); - - /* Create their index */ - createStreamInputIndexes(); - } - - /** - * Parses the metadata - * - * @throws CTFReaderException - */ - private void openTraceMetadata() throws CTFReaderException { - metadata.parse(); - } - - /** - * Creates the definitions needed by the Trace class to open the trace - * files. - */ - private void createDefinitions() { - if (packetHeaderDecl != null) { - packetHeaderDef = packetHeaderDecl.createDefinition(this, - "packet.header"); //$NON-NLS-1$ - } - } - - /** - * Creates the indexes of all the trace files. - * - * @throws CTFReaderException - */ - private void createStreamInputIndexes() throws CTFReaderException { - for (Map.Entry stream : streams.entrySet()) { - Set inputs = stream.getValue().getStreamInputs(); - for (StreamInput s : inputs) { - s.createIndex(); - } + /* + * Copy the events + */ + Iterator> it = s.getStream() + .getEvents().entrySet().iterator(); + while (it.hasNext()) { + Entry pairs = it.next(); + Long eventNum = pairs.getKey(); + IEventDeclaration eventDec = pairs.getValue(); + getEvents(s.getStream().getId()).put(eventNum, eventDec); } - } - - /** - * Tries to open every file in the trace directory (except metadata). - * - * @throws CTFReaderException - */ - private void openStreamInputs() throws CTFReaderException { - /* Create the definitions needed to read things from the files */ - createDefinitions(); - - /* List files not called metadata and not hidden. */ - File[] files = path.listFiles(new FileFilter() { - - @Override - public boolean accept(File pathname) { - - if (pathname.isDirectory()) { - return false; - } - - if (pathname.isHidden()) { - return false; - } - if (pathname.getName().equals("metadata")) { //$NON-NLS-1$ - return false; - } - - return true; - } - }); - Arrays.sort(files, new Comparator() { - - @Override - public int compare(File o1, File o2) { - - return o1.getName().compareTo(o2.getName()); - - } - }); - - /* Try to open each file */ - for (File s : files) { - openStreamInput(s); - } + /* + * 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. + * @param index + * 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 { - FileChannel streamFileChannel; + private Stream openStreamInput(File streamFile) throws CTFReaderException { MappedByteBuffer byteBuffer; BitBuffer streamBitBuffer; + Stream stream; + FileChannel fc; if (!streamFile.canRead()) { throw new CTFReaderException("Unreadable file : " //$NON-NLS-1$ + streamFile.getPath()); } + FileInputStream fis = null; try { /* Open the file and get the FileChannel */ - streamFileChannel = new FileInputStream(streamFile).getChannel(); + fis = new FileInputStream(streamFile); + fFileInputStreams.add(fis); + fc = fis.getChannel(); /* Map one memory page of 4 kiB */ - byteBuffer = streamFileChannel.map(MapMode.READ_ONLY, 0, 4096); + byteBuffer = fc.map(MapMode.READ_ONLY, 0, (int) Math.min(fc.size(), 4096L)); } catch (IOException e) { + if (fis != null) { + fFileInputStreams.remove(fis); + } /* 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 (fPacketHeaderDef != null) { /* Read the packet header */ - packetHeaderDef.read(streamBitBuffer); + fPacketHeaderDef.read(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$ - assert ((uuidDef != null) && (uuidDef.getDeclaration().getLength() == Utils.UUID_LEN)); + ArrayDefinition uuidDef = (ArrayDefinition) fPacketHeaderDef + .lookupDefinition("uuid"); //$NON-NLS-1$ if (uuidDef != null) { byte[] uuidArray = new byte[Utils.UUID_LEN]; for (int i = 0; i < Utils.UUID_LEN; i++) { - IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef.getElem(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 stream ID */ - // TODO: it hasn't been checked that the stream_id field exists and - // is an unsigned - // integer - IntegerDefinition streamIDDef = (IntegerDefinition) packetHeaderDef.lookupDefinition("stream_id"); //$NON-NLS-1$ - assert (streamIDDef != null); - - long streamID = streamIDDef.getValue(); - - /* Get the stream to which this trace file belongs to */ - Stream stream = streams.get(streamID); + /* Read the stream ID */ + Definition streamIDDef = fPacketHeaderDef.lookupDefinition("stream_id"); //$NON-NLS-1$ - /* Create the stream input */ - StreamInput streamInput = new StreamInput(stream, - streamFileChannel, streamFile); + if (streamIDDef instanceof IntegerDefinition) { // this doubles as a + // null check + long streamID = ((IntegerDefinition) streamIDDef).getValue(); + stream = fStreams.get(streamID); + } else { + /* No stream_id in the packet header */ + stream = fStreams.get(null); + } - /* Add a reference to the streamInput in the stream */ - stream.addInput(streamInput); } else { /* No packet header, we suppose there is only one stream */ - Stream stream = streams.get(null); - - /* Create the stream input */ - StreamInput streamInput = new StreamInput(stream, - streamFileChannel, streamFile); + stream = fStreams.get(null); + } - /* Add a reference to the streamInput in the stream */ - stream.addInput(streamInput); + if (stream == null) { + throw new CTFReaderException("Unexpected end of stream"); //$NON-NLS-1$ } + + /* Create the stream input */ + StreamInput streamInput = new StreamInput(stream, fc, streamFile); + + /* Add a reference to the streamInput in the stream */ + stream.addInput(streamInput); + + return stream; } /** @@ -561,26 +624,46 @@ public class CTFTrace implements IDefinitionScope { @Override public Definition lookupDefinition(String lookupPath) { if (lookupPath.equals("trace.packet.header")) { //$NON-NLS-1$ - return packetHeaderDef; + return fPacketHeaderDef; } return null; } /** - * 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 2.0 */ public void addStream(Stream stream) throws ParseException { + /* + * Init if not done before + */ + init(); + /* * 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$ } @@ -588,48 +671,287 @@ 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. + */ + Stream 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); + /* This stream is valid and has a unique id. */ + fStreams.put(stream.getId(), stream); } - public HashMap getEnvironment() { - return environment; + /** + * 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 Map getEnvironment() { + return Collections.unmodifiableMap(fEnvironment); } - public String lookupEnvironment( String key ) - { - return environment.get(key); + /** + * Add a variable to the environment variables + * + * @param varName + * the name of the variable + * @param varValue + * the value of the variable + */ + public void addEnvironmentVar(String varName, String varValue) { + fEnvironment.put(varName, varValue); } - public void addEnvironmentVar( String varName, String varValue) - { - environment.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 + */ + public void addClock(String nameValue, CTFClock ctfClock) { + fClocks.put(nameValue, ctfClock); } - public void addClock(String nameValue, CTFClock ctfClock) { - clocks.put(nameValue, ctfClock); + /** + * gets the clock with a specific name + * + * @param name + * the name of the clock. + * @return the clock + */ + public CTFClock getClock(String name) { + return fClocks.get(name); + } + + /** + * gets the clock if there is only one. (this is 100% of the use cases as of + * June 2012) + * + * @return the clock + */ + public final CTFClock getClock() { + if (fClocks.size() == 1) { + fSingleClock = fClocks.get(fClocks.keySet().iterator().next()); + return fSingleClock; + } + return null; + } + + /** + * gets the time offset of a clock with respect to UTC in nanoseconds + * + * @return the time offset of a clock with respect to UTC in nanoseconds + */ + public final long getOffset() { + if (getClock() == null) { + return 0; + } + return fSingleClock.getClockOffset(); + } + + /** + * gets the time offset of a clock with respect to UTC in nanoseconds + * + * @return the time offset of a clock with respect to UTC in nanoseconds + */ + private double getTimeScale() { + if (getClock() == null) { + return 1.0; + } + return fSingleClock.getClockScale(); + } + + /** + * Does the trace need to time scale? + * + * @return if the trace is in ns or cycles. + */ + private boolean clockNeedsScale() { + if (getClock() == null) { + return false; + } + return fSingleClock.isClockScaled(); } - public CTFClock getClock(String name){ - return clocks.get(name); + /** + * the inverse clock for returning to a scale. + * + * @return 1.0 / scale + */ + private double getInverseTimeScale() { + if (getClock() == null) { + return 1.0; + } + return fSingleClock.getClockAntiScale(); } - public CTFClock getClock(){ - if( clocks.size() == 1 ) - { - String key = (String) clocks.keySet().toArray()[0]; - return clocks.get(key); + /** + * @param cycles + * clock cycles since boot + * @return time in nanoseconds UTC offset + * @since 2.0 + */ + public long timestampCyclesToNanos(long cycles) { + long retVal = cycles + getOffset(); + /* + * this fix is since quite often the offset will be > than 53 bits and + * therefore the conversion will be lossy + */ + if (clockNeedsScale()) { + retVal = (long) (retVal * getTimeScale()); + } + return retVal; + } + + /** + * @param nanos + * time in nanoseconds UTC offset + * @return clock cycles since boot. + * @since 2.0 + */ + public long timestampNanoToCycles(long nanos) { + long retVal; + /* + * this fix is since quite often the offset will be > than 53 bits and + * therefore the conversion will be lossy + */ + if (clockNeedsScale()) { + retVal = (long) (nanos * getInverseTimeScale()); + } else { + retVal = nanos; + } + return retVal - getOffset(); + } + + /** + * 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 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 TreeSet getCallsiteCandidates(String eventName) { + TreeSet retVal = fCallsitesByName.get(eventName); + if (retVal == null) { + retVal = new TreeSet<>(fCtfCallsiteComparator); + } + return retVal; + } + + /** + * 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 CTFCallsite getCallsite(String eventName) { + TreeSet callsites = fCallsitesByName.get(eventName); + if (callsites != null) { + return callsites.first(); } 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 candidates = fCallsitesByName.get(eventName); + 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; + } +} + +class MetadataFileFilter implements FileFilter { + + @Override + public boolean accept(File pathname) { + if (pathname.isDirectory()) { + return false; + } + if (pathname.isHidden()) { + return false; + } + if (pathname.getName().equals("metadata")) { //$NON-NLS-1$ + return false; + } + return true; + } + +} + +class MetadataComparator implements Comparator, Serializable { + + private static final long serialVersionUID = 1L; + + @Override + public int compare(File o1, File o2) { + return o1.getName().compareTo(o2.getName()); + } }