/*******************************************************************************
- * Copyright (c) 2011-2013 Ericsson, Ecole Polytechnique de Montreal and others
+ * Copyright (c) 2011, 2013 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;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
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.CTFCallsiteComparator;
import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
-import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex;
/**
* A CTF trace on the file system.
*/
public class CTFTrace implements IDefinitionScope {
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#toString()
- */
@SuppressWarnings("nls")
@Override
public String toString() {
*/
private final File path;
- /**
- * The metadata parsing object.
- */
- private final Metadata metadata;
-
/**
* Major CTF version number
*/
/**
* Collection of streams contained in the trace.
*/
- private final Map<Long, Stream> streams = new HashMap<Long, Stream>();
+ private final Map<Long, Stream> streams = new HashMap<Long, Stream>();
/**
* Collection of environment variables set by the tracer
private final List<FileInputStream> fileInputStreams = new LinkedList<FileInputStream>();
/** Handlers for the metadata files */
- private final static FileFilter metadataFileFilter = new MetadataFileFilter();
- private final static Comparator<File> metadataComparator = new MetadataComparator(); // $codepro.audit.disable
- // fieldJavadoc
-
- /** map of all the event types */
- private final Map<Long,HashMap<Long, IEventDeclaration>> eventDecs = new HashMap<Long, HashMap<Long,IEventDeclaration>>();
- /** map of all the event types */
- private final Map<StreamInput,HashMap<Long, EventDefinition>> eventDefs = new HashMap<StreamInput, HashMap<Long,EventDefinition>>();
- /** map of all the indexes */
- private final Map<StreamInput, StreamInputPacketIndex> indexes = new HashMap<StreamInput, StreamInputPacketIndex>();
+ private static final FileFilter METADATA_FILE_FILTER = new MetadataFileFilter();
+ private static final Comparator<File> METADATA_COMPARATOR = new MetadataComparator();
/** Callsite helpers */
- private Map<String, LinkedList<CTFCallsite>> callsitesByName = new HashMap<String, LinkedList<CTFCallsite>>();
- /** Callsite helpers */
- private TreeSet<CTFCallsite> callsitesByIP = new TreeSet<CTFCallsite>();
+ private CTFCallsiteComparator ctfCallsiteComparator = new CTFCallsiteComparator();
+ private Map<String, TreeSet<CTFCallsite>> callsitesByName = new HashMap<String, TreeSet<CTFCallsite>>();
+ /** Callsite helpers */
+ private TreeSet<CTFCallsite> callsitesByIP = new TreeSet<CTFCallsite>();
// ------------------------------------------------------------------------
// Constructors
*/
public CTFTrace(File path) throws CTFReaderException {
this.path = path;
- this.metadata = new Metadata(this);
+ final Metadata metadata = new Metadata(this);
/* Set up the internal containers for this trace */
if (!this.path.exists()) {
/* 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$
+ 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);
+ 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 (Stream stream : getStreams()) {
+ Set<StreamInput> inputs = stream.getStreamInputs();
for (StreamInput s : inputs) {
/*
* Copy the events
/**
* Dispose the trace
+ *
* @since 2.0
*/
public void dispose() {
}
}
}
- System.gc(); // Invoke GC to release MappedByteBuffer objects (Java bug JDK-4724038)
+ // Invoke GC to release MappedByteBuffer objects (Java bug JDK-4724038)
+ System.gc();
}
// ------------------------------------------------------------------------
* @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, IEventDeclaration> getEvents(Long streamId) {
- return eventDecs.get(streamId);
- }
-
- /**
- * Gets an index for a given StreamInput
- * @param id the StreamInput
- * @return The index
- */
- StreamInputPacketIndex getIndex(StreamInput id){
- if(! indexes.containsKey(id)){
- indexes.put(id, new StreamInputPacketIndex());
- }
- return indexes.get(id);
+ public Map<Long, IEventDeclaration> getEvents(Long streamId) {
+ return streams.get(streamId).getEvents();
}
/**
* Gets an event Declaration hashmap for a given StreamInput
- * @param id the StreamInput
- * @return the hashmap with the event definitions
+ *
+ * @param id
+ * the StreamInput
+ * @return an empty hashmap, please see deprecated
* @since 2.0
+ * @deprecated You should be using
+ * {@link StreamInputReader#getEventDefinitions()} instead.
*/
- public HashMap<Long, EventDefinition> getEventDefs(StreamInput id) {
- if(! eventDefs.containsKey(id)){
- eventDefs.put(id, new HashMap<Long, EventDefinition>());
- }
- return eventDefs.get(id);
+ @Deprecated
+ public Map<Long, EventDefinition> getEventDefs(StreamInput id) {
+ return new HashMap<Long, EventDefinition>();
}
/**
}
/**
- * 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() {
+ public boolean majorIsSet() {
return major != null;
}
* Method UUIDIsSet is the UUID set?
*
* @return boolean is the UUID set?
+ * @since 2.0
*/
- public boolean UUIDIsSet() {
+ public boolean uuidIsSet() {
return uuid != null;
}
*
* @return ByteOrder gets the trace byte order
*/
- public ByteOrder getByteOrder() {
+ public final ByteOrder getByteOrder() {
return byteOrder;
}
}
/**
- * 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<Stream> an iterable over streams.
+ * @since 3.0
*/
- public Map<Long, Stream> getStreams() {
- return streams;
+ public Iterable<Stream> getStreams() {
+ return streams.values();
}
/**
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));
} 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 */
/* Read the stream ID */
Definition streamIDDef = packetHeaderDef.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);
} else {
stream = streams.get(null);
}
+ if (stream == null) {
+ throw new CTFReaderException("Unexpected end of stream"); //$NON-NLS-1$
+ }
+
/* Create the stream input */
StreamInput streamInput = new StreamInput(stream, fc, streamFile);
throw new ParseException("Stream id already exists"); //$NON-NLS-1$
}
- /* It should be ok now. */
+ /* This stream is valid and has a unique id. */
streams.put(stream.getId(), stream);
- eventDecs.put(stream.getId(), new HashMap<Long,IEventDeclaration>());
}
/**
- * gets the Environment variables from the trace metadata (See CTF spec)
- * @return the environment variables in a map form (key value)
+ * 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<String, String> getEnvironment() {
- return environment;
- }
-
- /**
- * Look up a specific environment variable
- * @param key the key to look for
- * @return the value of the variable, can be null.
- */
- public String lookupEnvironment(String key) {
- return environment.get(key);
+ return Collections.unmodifiableMap(environment);
}
/**
* 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);
/**
* 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);
/**
* 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);
}
-
-
-
/**
* gets the clock if there is only one. (this is 100% of the use cases as of
* June 2012)
*
* @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 if the trace is in ns or cycles.
*/
- private final boolean clockNeedsScale() {
+ private boolean clockNeedsScale() {
if (getClock() == null) {
return false;
}
*
* @return 1.0 / scale
*/
- private final double getInverseTimeScale() {
+ private double getInverseTimeScale() {
if (getClock() == null) {
return 1.0;
}
return retVal - getOffset();
}
- /**
- * Does a given stream contain any events?
- * @param id the stream ID
- * @return true if the stream has events.
- */
- public boolean hasEvents(Long id){
- return eventDecs.containsKey(id);
- }
-
- /**
- * Add an event declaration map to the events map.
- * @param id the id of a stream
- * @return the hashmap containing events.
- */
- public HashMap<Long, IEventDeclaration> createEvents(Long id){
- HashMap<Long, IEventDeclaration> value = eventDecs.get(id);
- if( value == null ) {
- value = new HashMap<Long, IEventDeclaration>();
- eventDecs.put(id, value);
- }
- return value;
- }
-
/**
* Adds a callsite
*
String fileName, long lineNumber) {
final CTFCallsite cs = new CTFCallsite(eventName, funcName, ip,
fileName, lineNumber);
- LinkedList<CTFCallsite> csl = callsitesByName.get(eventName);
+ TreeSet<CTFCallsite> csl = callsitesByName.get(eventName);
if (csl == null) {
- csl = new LinkedList<CTFCallsite>();
+ csl = new TreeSet<CTFCallsite>(ctfCallsiteComparator);
callsitesByName.put(eventName, csl);
}
- ListIterator<CTFCallsite> iter = csl.listIterator();
- int index = 0;
- for (; index < csl.size(); index++) {
- if (iter.next().compareTo(cs) < 0) {
- break;
- }
- }
-
- csl.add(index, cs);
+ csl.add(cs);
callsitesByIP.add(cs);
}
/**
- * Gets the list of callsites associated to an event name. O(1)
+ * Gets the set of callsites associated to an event name. O(1)
*
* @param eventName
* the event name
- * @return the callsite list can be empty
- * @since 1.2
+ * @return the callsite set can be empty
+ * @since 3.0
*/
- public List<CTFCallsite> getCallsiteCandidates(String eventName) {
- LinkedList<CTFCallsite> retVal = callsitesByName.get(eventName);
- if( retVal == null ) {
- retVal = new LinkedList<CTFCallsite>();
+ public TreeSet<CTFCallsite> getCallsiteCandidates(String eventName) {
+ TreeSet<CTFCallsite> retVal = callsitesByName.get(eventName);
+ if (retVal == null) {
+ retVal = new TreeSet<CTFCallsite>(ctfCallsiteComparator);
}
return retVal;
}
* @since 1.2
*/
public CTFCallsite getCallsite(String eventName) {
- return callsitesByName.get(eventName).getFirst();
+ TreeSet<CTFCallsite> callsites = callsitesByName.get(eventName);
+ if (callsites != null) {
+ return callsites.first();
+ }
+ return null;
}
/**
* @return the closest matching callsite, can be null
*/
public CTFCallsite getCallsite(String eventName, long ip) {
- final LinkedList<CTFCallsite> candidates = callsitesByName.get(eventName);
+ final TreeSet<CTFCallsite> candidates = callsitesByName.get(eventName);
final CTFCallsite dummyCs = new CTFCallsite(null, null, ip, null, -1);
- final int pos = Collections.binarySearch(candidates, dummyCs)+1;
- if( pos >= candidates.size()) {
- return null;
+ final CTFCallsite callsite = candidates.ceiling(dummyCs);
+ if (callsite == null) {
+ return candidates.floor(dummyCs);
}
- return candidates.get(pos);
+ return callsite;
}
-
}
class MetadataFileFilter implements FileFilter {